Skip to main content

Secondary Navigation

  • PHP Security Center
  • Blog
  • Store
  • Downloads
    • Downloads
    • Plugins
    • MyZend Account
  • Company
    • About Zend by Perforce
    • Careers at Perforce
    • Customers
    • Partners
    • Press
  • Contact
    • Contact Us
    • Request Pricing
    • Request Support
    • Subscribe
Home
Zend

Main Navigation - Mega Menu

  • Products

    Main Navigation - Mega Menu

    • ZendPHP
      PHP Runtime and Support
    • PHP LTS
      Patches for EOL PHP
    • ZendHQ
      Must-Have Extension for ZendPHP
    • Zend Server
      PHP Application Server
  • Services

    Main Navigation - Mega Menu

    • Service Overview
    • Migration Services
    • Audits
    • Custom Consulting
    • Admin as a Service
    • Zend Black Belt Services

    Services

    Innovate faster and cut risk with PHP experts from Zend Services.

    Explore Services

  • Solutions

    Main Navigation - Mega Menu

    • PHP Cloud Solutions
    • PHP Container Solutions
    • PHP Security Solutions
    • Windows Solutions
    • Hosting Provider Solutions

    Zend Solutions Cloud

    See How Zend Helps Leading Hosting Providers Keep Their Managed Sites on Secure PHP

    Read More

  • Training

    Main Navigation - Mega Menu

    • Training Overview
    • Zend PHP Certification

    Training

    Learn PHP from PHP experts with free, on-demand, and instructor led courses.

    Explore Training

  • Resources

    Main Navigation - Mega Menu

    • Explore Resources
    • Events & Webinars
    • Papers & Videos
    • Recorded Webinars
    • Blog
    Cloud Orchestration

    Orchestrating Your PHP Applications

    Watch Now
  • Support

    Main Navigation - Mega Menu

    • Explore Support
    • PHP Long-Term Support
    • Knowledgebase
    • Documentation
    • Download Software
    • Download Plugins
    • Request Support

    Support

    Submit support requests and browse self-service resources.

    Explore Support

  • Try Free
  • PHP Security Center
  • Blog
  • Store
  • Downloads

    Main Navigation - Mega Menu

    • Downloads
    • Plugins
    • MyZend Account
    • Downloads
    • Plugins
    • MyZend Account
  • Company

    Main Navigation - Mega Menu

    • About Zend by Perforce
    • Careers at Perforce
    • Customers
    • Partners
    • About Zend by Perforce
    • Careers at Perforce
    • Customers
    • Partners
  • Contact

    Main Navigation - Mega Menu

    • Contact Us
    • Request Support
    • Subscribe

TECHNICAL GUIDE

Writing PHP Extensions

Request PDF Version
Writing PHP Extensions
1. Setting up Your PHP Build Environment on Linux
2. Generating a PHP Extension Skeleton
3. Building and Installing a PHP Extension
4. Rebuilding Extensions for Production
5. Extension Skeleton File Content
6. Running PHP Extension Tests
7. Adding New Functionality
8. Basic PHP Structures
9. PHP Arrays
10. Catching Memory Leaks
11. PHP Memory Management
12. PHP References
13. Copy on Write
14. PHP Classes and Objects
15. Using OOP in our Example Extension
16. Embedding C Data into PHP Objects
17. Overriding Object Handlers
18. Answers to Common Extension Questions

5. Extension Skeleton File Content

Let’s review the contents of extension skeleton files.

“config.m4” is an extension configuration script, used during generation of “configure” script by “phpize” or “buildconf” commands. It’s written in M4 macro-processing language. Very basic knowledge is enough for PHP extension configuration. You can copy-paste blocks from this tutorial or other extension configuration files.

PHP_ARG_ENABLE([test],
    [whether to enable test support],
    [AS_HELP_STRING([--enable-test],
        [Enable test support])],
    [no])

if test "$PHP_TEST" != "no"; then
    AC_DEFINE(HAVE_TEST, 1, [ Have test support ])
    PHP_NEW_EXTENSION(test, test.c, $ext_shared)
fi

PHP_ARG_ENABLE(...) – macro adds a configuration option “--enable-test”. It may get three values “yes”, “no”, and “shared”. 

When you run “phpize”, the default value is “shared” which means we are going to build a dynamically loadable PHP extension. However, it is possible to copy the “test” extension directory into the main PHP distribution (“ext/test”) and  re-run “./buildconf”  and “./configure … –enable-test” to re-build the whole PHP with extension “test”, statically linked in. 

It’s possible to enable extension by default, replacing “no” to “yes” at line 5. In this case, it’s possible to disable “test” extension by “./configure --disable-test”.

Following “if” is just a regular UNIX shell code that tests the value defined by “--enable-test”, “--disable-test”, or “--enable-test=shared”.

AC_DEFINE(HAVE_TEST) adds C macro HAVE_TEST into “config.h”, so you can use conditional compilation directives (#ifdef, #ifndef) to skip useless code, if necessary.

Finally, the PHP_NEW_EXTENSION (test, test.c, $ext_shared) macro states that we are going to build extension “test” from “test.c” file. It’s possible to specify few files. Depending on the value of $ext_shared variable, the extension could be built as shared object or linked statically. (It’s taken from the same “--enable-test” option.)

This file might need to be extended in case you add new source files or need to link some external libraries. I’ll show how to link libraries later. Just, don’t forget to rerun “phpize”/”buildconf” + “configure” after you make any changes in this file.

Windows PHP uses a different build system. For Windows, file “config.w32” is a replacement of “config.m4”. The two are almost the same. They use similar macros, just a different language: on Windows PHP build system uses JavaScript instead of M4 and Shell. I won’t repeat the explanation of the macros. You should be able to guess.

ARG_ENABLE('test', 'test support', 'no');

if (PHP_TEST != 'no') {
    AC_DEFINE('HAVE_TEST', 1, 'test support enabled');
    EXTENSION('test', 'test.c', null, '/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1');
}

“php_test.h” is a C header file with common definitions. In our very basic case, it defines:

  • test_module_entry — an extension description structure. (It’s an entry point to the extension.)
  • PHP_TEST_VERSION — a version of the extension.
  • ZEND_TSRMLS_CACHE_EXTERN — a thread-local storage cache entry, if the extension was built for a thread-safe build (ZTS) and compiled as shared object ( COMPILE_DL_TEST).
/* test extension for PHP */

#ifndef PHP_TEST_H
# define PHP_TEST_H

extern zend_module_entry test_module_entry;
# define phpext_test_ptr &test_module_entry

# define PHP_TEST_VERSION "0.1.0"

# if defined(ZTS) && defined(COMPILE_DL_TEST)
ZEND_TSRMLS_CACHE_EXTERN()
# endif

#endif	/* PHP_TEST_H */

“test.c” is the main (and in our case, single) extension source file. It’s too big to fit into one page/screen, so I’ll split it into small parts and explain each part separately.

/* test extension for PHP */

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "php.h"
#include "ext/standard/info.h"
#include "php_test.h"

Include necessary C header files. You may add additional “#include” directives if necessary.

/* For compatibility with older PHP versions */
#ifndef ZEND_PARSE_PARAMETERS_NONE
#define ZEND_PARSE_PARAMETERS_NONE() \
    ZEND_PARSCE_PARAMETERS_START(0, 0) \
    ZEND_PARSE_PARAMETERS_END()
#endif

Some forward compatibility macro, to make it possible to compile the extension for older PHP-7 versions.

/* {{{ void test_test1()
 */
PHP_FUNCTION(test_test1)
{
    ZEND_PARSE_PARAMETERS_NONE();

    php_printf("The extension %s is loaded and working!\r\n", "test");
}
/* }}} */

A C code for function test_test1() provided by our PHP extension. The argument of PHP_FUNCTION() macro is the function name. ZEND_PARSE_PARAMETERS_NONE() tells that this function doesn’t require any arguments. php_printf(...) is just a C function call that prints the string into the output stream, similar to PHP printf() function.

/* {{{ string test_test2( [ string $var ] )
 */
PHP_FUNCTION(test_test2)
{
    char *var = "World";
    size_t var_len = sizeof("World") – 1;
    zend_string *retval;

    ZEND_PARSE_PARAMETERS_START(0, 1)
        Z_PARAM_OPTIONAL
        Z_PARAM_STRING(var, var_len)
    ZEND_PARSE_PARAMETERS_END();

    retval = strpprintf(0, "Hello %s", var);

    RETURN_STR(retval);
}
/* }}}*/

Another, more complex function uses “Fast Parameter Parsing API” to describe its arguments. 

ZEND_PARSE_PARAMETERS_START(0, 1) starts the parameter description section. Its first argument (0) defines the number of required arguments. 

The second argument (1) defines the maximum number of arguments. So, our function may be called without arguments, or with a single argument. 

Inside this section, we should define all parameters, their types, and where they will be copied. For our case:

  • Z_PARAM_OPTIONAL separates required parameters from optional ones. 
  • Z_PARAM_STRING() defines a string parameter that value is going to be copied to variable “var” and the length  into variable “var_len.” 

Note that our argument is optional and therefore may be omitted. In this case a default value “World” is used. See initializers for variables “var” and “var_len” above ZEND_PARSE_PARAMETERS_START.

The code creates a “zend_string” value and returns it though macro RETURN_STR() similar to PHP sprintf() function:

/* {{{ PHP_RINIT_FUNCTION
 */
PHP_RINIT_FUNCTION(test)
{
#if defined(ZTS) && defined(COMPILE_DL_TEST)
    ZEND_TSRMLS_CACHE_UPDATE();
#endif

    return SUCCESS;
}
/* }}} */

PHP_RINIT_FUNCTION() defines a callback function that is going to be called at each request start-up. In our case, it only initializes thread-local storage cache. It would be much better to do this early (in MINIT or GINIT callbacks). I predict this will be fixed in the PHP 8 extension skeleton.

/* {{{ PHP_MINFO_FUNCTION
 */
PHP_MINFO_FUNCTION(test)
{
    php_info_print_table_start();
    php_info_print_table_header(2, "test support", "enabled");
    php_info_print_table_end();
}
/* }}} */

PHP_MINFO_FUNCTION() defines a callback function that is going to be called from PHP phpinfo() function, to print information about the extension.

/* {{{ arginfo
    */
ZEND_BEGIN_ARG_INFO(arginfo_test_test1, 0)
ZEND_END_ARG_INFO()

Information about arguments of the first function. There are no arguments.

ZEND_BEGIN_ARG_INFO(arginfo_test_test2, 0)
    ZEND_ARG_INFO(0, str)
ZEND_END_ARG_INFO()
/* }}} */

Information about arguments of the second function. The single optional argument with name “str” is passed by value.

/* {{{ test_functions[]
 */
static const zend_function_entry test_functions[] = {
    PHP_FE(test_test1,		arginfo_test_test1)
    PHP_FE(test_test2,		arginfo_test_test2)
    PHP_FE_END
};
/* }}} */

“test_functions” is a list of all extension functions with information about their arguments. The list is terminated by PHP_FE_END macro.

/* {{{ test_module_entry
 */
zend_module_entry test_module_entry = {
    STANDARD_MODULE_HEADER,
    "test",				/* Extension name */
    test_functions,			/* zend_function_entry */
    NULL,				/* PHP_MINIT - Module initialization */
    NULL,				/* PHP_MSHUTDOWN - Module shutdown */
    PHP_RINIT(test),			/* PHP_RINIT - Request initialization */
    NULL,				/* PHP_RSHUTDOWN - Request shutdown */
    PHP_MINFO(test),			/* PHP_MINFO - Module info */
    PHP_TEST_VERSION,			/* Version */
    STANDARD_MODULE_PROPERTIES
};
/* }}} */

test_module_entry is the main extension entry structure. PHP core takes all information about extensions from such structures. It defines:

  • Extension name (“test”).
  • A list of declared PHP functions (“test_functions”).
  • A few callback functions and extension version (PHP_TEST_VERSION - defined in the header file). 

The callbacks occur when PHP started (MINIT), on PHP termination (MSHUTDOWN), at start of each request processing (RINIT), at the end of each request processing (RSHUTDOWN) and from phpinfo() (MINFO).

#ifdef COMPILE_DL_TEST
# ifdef ZTS
ZEND_TSRMLS_CACHE_DEFINE()
# endif
ZEND_GET_MODULE(test)
#endif

Finally, a couple of definitions for dynamic linking.

Request PDF Version

Book traversal links for 5. Extension Skeleton File Content

  • ‹ 4. Rebuilding Extensions for Production
  • Writing PHP Extensions
  • 6. Running PHP Extension Tests ›

Footer menu

  • Products
    • ZendPHP
    • PHP Long-Term Support
    • ZendHQ
    • Zend Server
    • Laminas Enterprise Support
    • PHP Development Tools
  • Services
    • PHP Long-Term Support
    • Migration Services
    • Audits
    • CI/CD Services
    • Custom Consulting
    • Admin as a Service
  • Free Trials and Demos
    • ZendPHP Trial
    • Zend Server Trial
    • ZendHQ Demo
  • Training
  • Resources
    • PHP Security Center
    • Papers & Videos
    • Events & Webinars
    • Recorded Webinars
    • Blog
    • Case Studies
  • Hubs
    • PHP Versions Guide
    • Developing Web Apps With PHP
    • Guide to PHP and IBM i
    • PHP Security
  • Store
  • Downloads
    • MyZend Account
    • Plugins
    • Container Registry
  • Support
    • PHP Long-term Support
    • Knowledgebase
    • Documentation
    • Software End of Life Policy
  • Contact
    • Request Pricing
    • Request Support
    • Subscribe
  • Company
    • About Zend by Perforce
    • Careers at Perforce
    • Customers
    • Partners
    • Press
Home

Zend by Perforce © Perforce Software, Inc.
Terms of Use  |  Privacy Policy | Sitemap

Social Menu

  • Facebook
  • LinkedIn
  • Twitter
  • YouTube
  • RSS
Send Feedback