This article is based on PHP7.4 and explains how to create a PHP extension from scratch. This article will explain the basic steps to create an extension. In the example, we will implement the following functionality.

1
2
3
<?php

echo hello();

Output content:

1
2
3
// $ php74 ./hello.php

$ hello word

Implement a hello method in the extension to output hello word! after calling the hello method.

Generating the extension archetype

First we need to have a copy of php-src.

1
2
3
4
5
git clone https://github.com/php/php-src.git 
cd php-src
git checkout PHP-7.4.5
cd php-7.4.10/ext
ls

You can see that there is an ext_skel.php file.

1
2
3
bcmath    com_dotnet  date  enchant       ffi       ftp      gmp    imap  ldap      mysqli   odbc     pcntl  pdo_dblib     pdo_oci    pdo_sqlite  posix     reflection  simplexml  soap     spl       sysvmsg  tidy       xmlreader  xsl        zlib
bz2       ctype       dba   exif          fileinfo  gd       hash   intl  libxml    mysqlnd  opcache  pcre   pdo_firebird  pdo_odbc   pgsql       pspell    session     skeleton   sockets  sqlite3   sysvsem  tokenizer  xmlrpc     zend_test
calendar  curl        dom   ext_skel.php  filter    gettext  iconv  json  mbstring  oci8     openssl  pdo    pdo_mysql     pdo_pgsql  phar        readline  shmop       snmp       sodium   standard  sysvshm  xml        xmlwriter  zip

This file is already distributed with php, so we can customize it very easily.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
php ext_skel.php --ext hello --author aoppp --std

Copying config scripts... done
Copying sources... done
Copying tests... done

Success. The extension is now ready to be compiled. To do so, use the
following steps:

cd /path/to/php-src/hello
phpize
./configure
make

Don't forget to run tests once the compilation is done:
make test

Thank you for using PHP!

The hello directory is created in the ext directory.

Extended Archetype Description

1
2
3
4
5
6
7
-rw-r--r--   1 longshilin  staff   405 Feb 27 16:07 .gitignore
-rw-r--r--   1 longshilin  staff    11 Feb 27 16:07 CREDITS
-rw-r--r--   1 longshilin  staff  3231 Feb 27 16:07 config.m4
-rw-r--r--   1 longshilin  staff   204 Feb 27 16:07 config.w32
-rw-r--r--   1 longshilin  staff  3355 Feb 27 16:07 hello.c
-rw-r--r--   1 longshilin  staff  1425 Feb 27 16:07 php_hello.h
drwxr-xr-x   5 longshilin  staff   160 Feb 27 16:07 tests
  • config.m4 configuration file

    The extended config.m4 file tells the UNIX build system which extension configure options are supported, which extension libraries you need, and which source files to compile as part of it. For all frequently used autoconf macros, including PHP specific and autoconf built-in ones.

    The purpose of config.m4 is to generate configure files in conjunction with the phpize utility. The configure file is used for environment testing. It checks if the environment required for the extension to compile and run is met. Now let’s start modifying the config.m4 file.

    config.m4

    where dnl is a comment symbol.

    The above code says that if you write an extension that depends on other extensions or lib libraries, you need to uncomment the PHP_ARG_WITH related code. Otherwise, remove the comments from the PHP_ARG_ENABLE related code snippet. We write extensions that do not depend on other extensions and lib libraries. Therefore, we remove the comment before PHP_ARG_ENABLE.

    The above image is generated with the specification that it does not depend on other extensions.

  • php_hello.h header file Similar to the C header file, it contains some custom structures and function declarations, which need not be changed in this demo for now.

  • hello.c code file

    The real logic code is in this file.

Write the code

hello.c is all logic code inside, so we just add code to operate in this file.

Understanding the extension entry

The entry point for the entire extension is the zend_module_entry structure, the specific definition can be seen in the zend_modules.h file in the Zend directory, there are a dozen attributes, quick skip, we only need hello for now.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
zend_module_entry hello_module_entry = {
    STANDARD_MODULE_HEADER,
    "hello",                    /* Extension name */
    hello_functions,            /* zend_function_entry */
    NULL,                       /* PHP_MINIT - Module initialization */
    NULL,                       /* PHP_MSHUTDOWN - Module shutdown */
    PHP_RINIT(hello),           /* PHP_RINIT - Request initialization */
    NULL,                       /* PHP_RSHUTDOWN - Request shutdown */
    PHP_MINFO(hello),           /* PHP_MINFO - Module info */
    PHP_HELLO_VERSION,          /* Version */
    STANDARD_MODULE_PROPERTIES
};

Extension-related properties description:

  • STANDARD_MODULE_HEADER helps us to implement the first 6 properties
  • hello is the name of the extension
  • hello_functions is the set of all methods contained in the extension, followed by 5 macros for each of the 5 extension-specific methods
  • PHP_HELLO_VERSION is the version number of the extension, defined in the header file, so if you need to change it, just open php_hello.h and find define PHP_LZPAY_VERSION.
  • STANDARD_MODULE_PROPERTIES does the rest of the properties for us

In the hello_functions[] method array there are already 2 example methods hello_test1 and hello_test2, we refer to them to write our methods, first we write a test method and put it after the function PHP_FUNCTION(hello_test2).

1
2
3
4
5
6
7
/*新增函数*/
PHP_FUNCTION(hello)
{
     zend_string *strg;
     strg = strpprintf(0, "hello word");
     RETURN_STR(strg);
}

Then add our newly written functions to the hello_functions[] array.

hello_functions[] array

Compile and install

Since I have a new standalone installation of php7.4, I’m basically operating with absolute paths. If you have one environment, then just do it directly.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
cd hello/
/usr/local/Cellar/php/7.4.0/bin/phpize
./configure  --with-php-config=/usr/local/Cellar/php/7.4.0/bin/php-config
make && make install

----------------------------------------------------------------------------
Build complete.
Don't forget to run 'make test'.

Installing shared extensions:     /usr/local/Cellar/php/7.4.0/pecl/20190902/

Once installed, let’s configure the extension.

  • ext-hello.ini
1
2
[hello]
extension="/usr/local/Cellar/php/7.4.0/pecl/20190902/hello.so"

Testing

1
2
3
hello git:(PHP-7.4.5) $ /usr/local/Cellar/php/7.4.0/bin/php -m | grep hello
# 输出成功说明ok
hello

php