One, foreword
1. The source code version used in this article is PHP-7.1.19
2. The PHP version installed in this article is 7.1.19
3. If the computer is A Mac, the operating system information is as follows
Darwin Kernel Version 18.0.0: root:xnu-4903.201.2~1/RELEASE_X86_64 x86_64
Copy the code
4. The extension development mentioned in this article is a PHP extension, not a Zend extension
5, the original article from the blog, pay attention to get the latest articles
PHP extensions and Zend extensions
1. What are PHP extensions
The _zend_module_entry structure is defined in the /php-src/Zend/zend_modules.h header. This structure is the PHP extension structure called module, which provides the following hook functions in addition to some basic information
MINT
: is called when the module is initializedMSHUTDOWN
: is called when the module terminatesRINT
: is called every time a request is madeRSHUTDOWN
: Is invoked after each request ends
struct _zend_module_entry {
// The basic information is normally populated with the STANDARD_MODULE_HEADER constant
unsigned short size;
unsigned int zend_api;
const struct _zend_ini_entry *ini_entry;
int module_started;
int module_number;
// Name of the extension
const char *name;
// Extended function pointer, used to get the list of extended functions
const struct _zend_function_entry *functions;
// MINT hook function
int (*module_startup_func)(INIT_FUNC_ARGS);
// MSHUTDOWN hook function
int (*module_shutdown_func)(SHUTDOWN_FUNC_ARGS);
// RINT hook function
int (*request_startup_func)(INIT_FUNC_ARGS);
// RSHUTDOWN hook function
int (*request_shutdown_func)(SHUTDOWN_FUNC_ARGS);
// Prints extended information when phpInfo () is called
void (*info_func)(ZEND_MODULE_INFO_FUNC_ARGS);
};
Copy the code
What is the Zend extension
The _zend_extension structure is defined in the /php-src/Zend/zend_extensions.h header. This structure is the structure of the Zend extension, called extension. More low-level hook functions are provided than PHP extensions, as shown below
struct _zend_extension {
// Some basic information
char *name;
char *version;
char *author;
char *URL;
char *copyright;
/* Some hook functions within the Zend lifecycle */
startup_func_t startup;
shutdown_func_t shutdown;
activate_func_t activate;
deactivate_func_t deactivate;
message_handler_func_t message_handler;
op_array_handler_func_t op_array_handler;
statement_handler_func_t statement_handler;
fcall_begin_handler_func_t fcall_begin_handler;
fcall_end_handler_func_t fcall_end_handler;
op_array_ctor_func_t op_array_ctor;
op_array_dtor_func_t op_array_dtor;
/* Some hook functions within the Zend lifecycle */
};
Copy the code
3, for example,
(1) the Json extension
The Json extension defines the structure as zend_module_entry, which indicates that it is a PHP extension
(2) Opcache extension
The Opcache extension defines zend_extension as a Zend extension
(3) the Xdebug extension
The Xdebug extension must Hook within the Zend lifecycle to debug code, so Xdebug is a Zend extension
4, summarize
Extensions distinguish between PHP extensions and Zend extensions, and there is a strict distinction between module and extension in PHP source code
module
saidphp extension
, which is a PHP extension loaded with extension=*extension
saidzend extension
, the Zend extension, loaded with zend_extension=*
Third, the structure of the extension
1. Directory structure
The php-src/ext directory in the source code is the extension directory, such as JSON, mysqli, pDO and other commonly used extensions, each of which is mainly composed of the following files
tests
: Unit test directoryconfig.m4
: Extended build configuration file (Unix)config.w32
: Extended build configuration file (Windows)php_{$module}.h
: Extension header file{$module}.c
: Extends the source file{$module}.php
: extended test file
2. Code structure
(1) Unit test
After the extension is successfully compiled, a run-test.php script file is generated in the extension directory, which automatically performs all unit tests in the Tests directory. In addition, in the extension directory will automatically generate a {$module}.php extension test file, you can easily test whether the extension can be loaded and used normally
(2) Compile the configuration file
So extension files can be used by PHP. Config. m4 and config.w32 are the configuration files that will be used in the subsequent execution of PHPize. M4 is a macro processing file consisting of PHP_ARG_WITH and PHP_ARG_ENABLE. The second part is used to enable the specified extension. At compile time, the $PHP_PHP_HELLO variable is determined not to be no, and the compilation of this extension is performed. If you want to compile the php_hello extension, remove all the DNL macros at the beginning of the PHP_ARG_ENABLE section
dnl If your extension references something external, use with:
dnl PHP_ARG_WITH(php_hello.for php_hello support.dnl Make sure that the comment is aligned:
dnl[-with-php_hello Include php_hello support])
dnl Otherwise use enable:
dnl PHP_ARG_ENABLE(php_hello.whether to enable php_hello support.dnl Make sure that the comment is aligned:
dnl[-enable-php_hello Enable php_hello support])
if test "$PHP_PHP_HELLO! "" ="no"; then
PHP_NEW_EXTENSION(php_hello, php_hello.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
fi
Copy the code
(3) Extension header file
The extension header, usually named php_{$module}. H, is used to define constants, functions, etc
(4) Expand the source file
The extension source file, typically named {$module}.c, consists of the following sections
zend_module_entry
: Defines the extended structurePHP_FUNCTION
: Defines the extended functionHook_FUNCTION
, such as:PHP_MINIT_FUNCTION
等
The loading process of the extension
(1) Source annotations
In the php-src/main/main.c file, the php_module_startup() function performs the load and initialization of the extension.
int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_modules, uint num_additional_modules)
{
// Zend engine initialization
zend_startup(&zuf, NULL);
// Register constants
php_output_register_constants();
php_rfc1867_register_constants();
// Register the INI configuration
if (php_init_config() == FAILURE) {
return FAILURE;
}
REGISTER_INI_ENTRIES();
zend_register_standard_ini_entries();
// register global variables like $_GET/$_POST/$_SERVER/$_REQUEST
php_startup_auto_globals()
// Load statically compiled extensions included in main/internal_functions.c
if (php_register_internal_extensions_func(TSRMLS_C) == FAILURE) {
php_printf("Unable to start builtin modules\n");
return FAILURE;
}
// Register the SAPI extension module, i.e. Additional_modules
php_register_extensions_bc(additional_modules, num_additional_modules TSRMLS_CC);
// According to ini configuration, load Zend extension first, then load PHP extension
php_ini_register_extensions(TSRMLS_C);
// Extension initialization triggers MINT() hook
zend_startup_modules(TSRMLS_C);
zend_startup_extensions();
}
Copy the code
(2) php_ini_register_extensions function
In this function, extension_lists is a linked list of all extensions obtained after parsing ini configurations (including PHP extensions and Zend extensions), Get PHP extended lists and Zend extended lists by using &extension_lists. Engine and &extension_lists. Functions. The different types of extensions are then loaded by php_load_zend_extension_cb() or php_load_PHp_extension_CB (), respectively
void php_ini_register_extensions(void)
{
// Register the Zend extension
zend_llist_apply(&extension_lists.engine, php_load_zend_extension_cb);
// Register the PHP extension
zend_llist_apply(&extension_lists.functions, php_load_php_extension_cb);
zend_llist_destroy(&extension_lists.engine);
zend_llist_destroy(&extension_lists.functions);
}
Copy the code
(3) Extended life cycle
As you can see in the PHP Extensions and Zend extensions section, the two extensions provide different hook functions, which are called in the order shown in the following figure throughout the PHP life cycle
Five, extended development tutorial
1. Get the PHP source code
After obtaining the PHP source code, switch to version 7.1.19 and follow the following command
git clonehttps://github.com/php/php-src git checkout remotes/origin/PHP - 7.1.19Copy the code
2. Generate the base file for the extension
Switch to the ext extension directory, where you have an ext_skel script that can be used to automatically generate the base files for the extension. For example, to create an extension to print_hello, do the following
cd php-src/ext/
./ext_skel --extname=print_hello
Copy the code
After the command is executed successfully, the following message is displayed
The print_hello directory has been successfully generated and contains the following files
tests
: Unit test directoryconfig.m4
: Extended build configuration file (Unix)config.w32
: Extended build configuration file (Windows)php_print_hello.h
: Extension header fileprint_hello.c
: Extends the source fileprint_hello.php
: extended test file
3. Modify the compilation configuration file
Open the config.m4 configuration file, as shown below
Find the PHP_ARG_ENABLE code and delete the DNL macro, as shown below
# change before
dnl PHP_ARG_ENABLE(print_hello, whether to enable print_hello support,
dnl Make sure that the comment is aligned:
dnl [ --enable-print_hello Enable print_hello support])
# modified
PHP_ARG_ENABLE(print_hello, whether to enable print_hello support,
Make sure that the comment is aligned:
[ --enable-print_hello Enable print_hello support])
Copy the code
4. Modify the print_hello.c file
Find PHP_FUNCTION (which represents the defined extension function) and add one line of code that prints Hello World to the confirm_print_hello_compiled function as follows
PHP_FUNCTION(confirm_print_hello_compiled)
{
char *arg = NULL;
size_t arg_len, len;
zend_string *strg;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &arg, &arg_len) == FAILURE) {
return;
}
strg = strpprintf(0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP."."print_hello", arg); // Add php_printf()"hello world! \n");
RETURN_STR(strg);
}
Copy the code
5. Build the extension
Compile processing of the extension by executing the following command
cd print_hello
phpize
./configure --with-php-config=/usr/bin/php-config
make
sudo make
Copy the code
The following information is displayed after the make command is executed successfully
The following information is displayed after the sudo make install command is executed successfully
6. Execute the extended test script
The test script dynamically loads the print_hello extension and prints all the functions provided in the extension. Finally, the confirm_print_hello_compiled function defined in the print_hello.c source file is executed, indicating that the extension is loaded and executed successfully
$br = (php_sapi_name() == "cli")? "":"<br>";
// Check whether the extension is loaded
if(! extension_loaded('print_hello')) {
// Load the extension library dynamically at runtime
// If the loading fails, you need to modify the php.ini configuration file. Directly enable the option enable_dl = On to dynamically load the extension
dl('print_hello.' . PHP_SHLIB_SUFFIX);
}
$module = 'print_hello';
// Outputs all functions provided by the extension in turn
$functions = get_extension_funcs($module);
echo "Functions available in the test extension:$br\n";
foreach($functions as $func) {
echo $func."$br\n";
}
echo "$br\n";
If the extension loads successfully, the confirm_print_hello_compiled function is executed
$function = 'confirm_' . $module . '_compiled';
if (extension_loaded($module)) {
$str = $function($module);
} else {
$str = "Module $module is not compiled into PHP";
}
echo "$str\n";
Copy the code
The following information is displayed after the script is successfully executed
In July and end
So far, a simple print_Hello extension has been developed, and of course you can define more extension functions in the print_hello.c source file and do more fun things! For advanced use of the extension, please check out the blog for the latest articles!