« Back to article list

Creating a PHP 7 Extension

Table of Contents

Creating a PHP 7 Extension - why?

Why would you want to do such a thing?

Perhaps you enjoy programming in C (or want a break from coding in PHP), yet you still want your end result to be usable in your PHP codebase.

Or, perhaps you're doing it for performance reasons.

Perhaps curiosity, or perhaps all of the above.

Why write about it?

When I went to look this up on my own, I noticed that most the articles detailing this process were quite old (aimed at PHP 4 and 5), and following them verbatim did not work for various reasons.

I hope to save you (the reader) some time, by being able to go step by step and type along to get you started.

Getting started

Download the source

To begin with, get a copy of the latest PHP 7 source code from here:

http://php.net/downloads.php

After the download ends (you'll have to choose a mirror) you can then decompress the archive (if you intend to create a PHP extension, I hope you know how to do this…).

Navigate to the extension directory and run a program

You're then going to cd into the extension directory, 'ext', and run the following command:

./ext_skel --extname=hello

You should see some output similar to the following:

Creating directory hello
Creating basic files: config.m4 config.w32 .gitignore hello.c php_hello.h CREDITS EXPERIMENTAL tests/001.phpt hello.php [done].

To use your new extension, you will have to execute the following steps:

1.  $ cd ..
2.  $ vi ext/hello/config.m4
3.  $ ./buildconf
4.  $ ./configure --[with|enable]-hello
5.  $ make
6.  $ ./sapi/cli/php -f ext/hello/hello.php
7.  $ vi ext/hello/hello.c
8.  $ make

Repeat steps 3-6 until you are satisfied with ext/hello/config.m4 and
step 6 confirms that your module is compiled into PHP. Then, start writing
code and repeat the last two steps as often as necessary.

What do you think you should do next?

If you guessed follow the instructions presented, you're (mostly) right!

Customizing the skeleton files for your extension build

So, some of the steps the skeleton program told us to do are not 100% correct, and I found the most direct route to get to the point of the extension working was as follows:

Configuring config.m4

First off, open this file as indicated in your editor of choice, and make the following updates (customize it later as you need).

Uncomment lines 16 to 18, so your file has an uncommented section that looks like this (including line breaks at those spots):

PHP_ARG_ENABLE(hello, whether to enable hello support,
Make sure that the comment is aligned:
[  --enable-hello           Enable hello support])

Then go down to line 53 and uncomment the AC_DEFINE (for this very basic example, it will work without the wrapper check around it) so that it looks like this:

AC_DEFINE(HAVE_HELLOLIB,1,[ ])

Lastly, save and quit the file.

Diverging a little…

So, one thing that the instructions above mentioned were to run buildconf and configure up at the top level (as well as make).

That is going to build the entire PHP 7 distro from source.

I'm assuming most readers already have a PHP 7 distro set up that can load extension.so files, so this is a bit overkill for creating a simple Hello World extension.

So, ignore the advice given from the ext_skel command, and instead make sure you're in the ext/hello directory, and run the following:

phpize

This will set up the configure scripts directly in this directory, based on what was read from the config.m4 file.

Next up, run:

./configure --enable-hello

You should see it produced Makefiles.

Updating the source file

Now, open up your hello.c file, and lets add another custom function (in addition to the one that confirms the extension built successfully).

Jump down to line 74 and add the following:

/* {{{ proto string hello_world(string arg)
   Say Hello World to everyone */
PHP_FUNCTION(hello_world)
{
    RETURN_STRING("Hello world");
}
/* }}} */

The weird comments have to do with code folding in emacs/vim and is recommended within the PHP extension files as a best practice (so I suggest leaving it there if I were you).

Now jump down to line 155 and update it to look like this (it's just adding one line actually):

const zend_function_entry hello_functions[] = {
    PHP_FE(confirm_hello_compiled,  NULL)       /* For testing, remove later. */
    PHP_FE(hello_world, NULL)
    PHP_FE_END  /* Must be the last line in hello_functions[] */
};

This registers our new 'hello_world' function.

Compiling

Save and exit your hello.c file and type the standard:

make

At this point, you should now see a file in modules/hello.so if everything went as planned.

Update your existing environment

Now, copy or symlink this hello.so module into your system specific modules directory (I use Arch Linux, and it is located at /usr/lib/php/modules for me).

After this is done, if you type:

php -i | grep hello

You should see your module is loaded in the ini output.

Test the module

There is a script in the ext/hello directory which will print out all your extension's defined functions, so give it a go with:

php hello.php

You should see some output that indicates a success.

You can also directly test your new call via:

php -r 'echo hello_world();'

Discuss

<div id="disqus_thread"></div> <script type="text/javascript"> * * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * * var disqus_shortname = 'ahungry'; // required: replace example with your forum shortname

* * * DON'T EDIT BELOW THIS LINE * * * (function() { var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js'; (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); })(); </script> <noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> <a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>