Every php extension requires at least two files: one configuration file, which tells the compiling phase which files are to be built and what external libraries are required, and at least one source file is required, it performs the actual work. your first extension
Every php extension requires at least two files: one configuration file, which tells the compiling phase which files are to be built and what external libraries are required, and at least one source file is required, it performs the actual work.
Profiling extension
In fact, there will usually be a second or third configuration file and one or more header files. for your first extension, you need to add a file of each type and use it to work.
Configuration file
To get started, first create a directory named sample under the ext/directory of your php source code directory tree. in fact, this new directory can be stored anywhere, but to demonstrate win32 and static build options later in this chapter, we should first establish it under the source code directory.
Next, go to the Directory, create a file named config. m4, and type the following content:
PHP_ARG_ENABLE(sample, [Whether to enable the "sample" extension], [ enable-sample Enable "sample" extension support]) if test $PHP_SAMPLE != "no"; then PHP_SUBST(SAMPLE_SHARED_LIBADD) PHP_NEW_EXTENSION(sample, sample.c, $ext_shared) fi
This is. /The minimum requirement for the enable-sample option to be called during configure. the second parameter of PHP_ARG_ENABLE will be in. /displayed when the extended configuration file is reached during configure processing. the third parameter will be executed by the end user. /configure -- help is displayed as help information.
Have you ever wondered why some extension configurations use enable-extname, while some extensions use with-extname? There is no difference in functionality between the two. In fact, enable indicates that this feature is enabled without any third-party libraries. In contrast, with indicates that there are other prerequisites for using this feature.
Now, your sample extension does not need to be linked to other libraries, so you only need to use the enable version. in chapter 17th "external library", we will introduce the use of with and instruct the compiler to use additional CFLAGS and LDFLAGS settings.
If the end user uses the enable-sample option. /configure, then the local environment variable $ PHP_SAMPLE will be set to yes. PHP_SUBST () is a php modified version of the AC_SUBST () macro of the standard autoconf. it is required to build the extension into a shared module.
Last but not least. PHP_NEW_EXTENSION () defines the module and enumerates all the source files that must be compiled as part of the extension. if you need multiple files, it can be separated by spaces in the second parameter, for example:
PHP_NEW_EXTENSION(sample, sample.c sample2.c sample3.c, $ext_shared)
The last parameter corresponds to the PHP_SUBST (SAMPLE_SHARED_LIBADD) command, which is also required when building a shared module.
Header file
When C is used for development, it is common to isolate data type definitions from external header files by including source files. although php does not require this, it simplifies the process when the module grows to a single source file.
In your php_sample.h header file, start with the following content:
# Ifndef PHP_SAMPLE_H/* prevent repeated inclusion of */# define PHP_SAMPLE_H/* define extended attributes */# define PHP_SAMPLE_EXTNAME "sample" # define PHP_SAMPLE_EXTVER "1.0"/* outside the php source code tree introduce the configuration option */# ifdef HAVE_CONFIG_H # include "config. h "# endif/* contains the php Standard header file */# include" php. h "/* defines the entry point symbol. when Zend loads this module, use */extern zend_module_entry sample_module_entry; # define phpext_sample_ptr & sample_module_entry # endif/* PHP_SAMPLE_H */
This header file completes two main tasks: if the extension is built using the phpize tool (this method is usually used in this book), HAVE_CONFG_H is defined, so config. h will be normally included. no matter how the extension is compiled, php will be included in the php source code tree. h. this header file contains other header files used to access most php APIs in the php source code.
Next, the zend_module_entry structure used by your extension is defined as external, so that when this module is loaded with extension = xxx, it can be obtained by Zend using dlopen and dlsym.
For more information about the module loading process, see the translator's blog. <从dl('xxx.so');函数分析php模块开发> Http://blog.csdn.Net/lgg201/article/details/6584095)
The header file also contains some preprocessing, defining the information that will be used in the original file.
Source code
Finally, you need to create a simple source code skeleton in sample. c:
#include "php_sample.h" zend_module_entry sample_module_entry = { #if ZEND_MODULE_API_NO >= 20010901 STANDARD_MODULE_HEADER, #endif PHP_SAMPLE_EXTNAME, NULL, /* Functions */ NULL, /* MINIT */ NULL, /* MSHUTDOWN */ NULL, /* RINIT */ NULL, /* RSHUTDOWN */ NULL, /* MINFO */ #if ZEND_MODULE_API_NO >= 20010901 PHP_SAMPLE_EXTVER, #endif STANDARD_MODULE_PROPERTIES }; #ifdef COMPILE_DL_SAMPLE ZEND_GET_MODULE(sample) #endif
This is simple. these three files are all required to create a module skeleton. however, it does not have any functions, but it is a good choice as a template for filling the function after this section. but let's see what happened first.
The first line is very simple. it contains the header file you just created and other kernel header files in the php source code tree are obtained through extension.
Next, create the zend_module_entry structure defined in the header file. you should note that the first element of zend_module_entry is a conditional expression that is defined by ZEND_MODULE_API_NO. this API number is probably php4.2.0. if you are sure that your extension will not be installed in a later version, you can cut down the # ifdef part and directly include the STANDARD_MODULE_HEADER element.
In any case, it will take a little time during the compilation period, without affecting the time required for the binary or processing of the results. Therefore, it is best to cut down this condition directly in most cases. this applies to the following version attributes.
The other six elements are now initially set to NULL; you can see its purpose in the comments behind it.
Finally, you can see at the bottom that every php extension that can be compiled as a shared module has a common element. this short condition adds a reference by Zend during dynamic loading. do not care about its details. you only need to ensure its existence. Otherwise, it may not work in the next section.
Build your first extension
Now that you have all the files, it is time to compile and install. compared with compiling the main php binary, the steps are slightly different.
Built on * nix
The first step is to use the information in config. m4 as the last class to generate a./configure script. this can be done by running the phpize program installed with the binary code of the main php installation:
$ phpize PHP Api Version: 20041225 Zend Module Api No: 20050617 Zend Extension Api No: 220050617
Zend Extension Api No. 2 is not a printing error. it corresponds to the Zend Engine 2 version and is generally considered to be larger than the corresponding ZE1 version.
If you view the current directory, you will notice that there are more files than the three files. the phpize program combines your expanded config. m4 files and information collected from your php build and everything you need to make compilation happen. this means that you do not need to get entangled in makefile and locate the php header. php has already helped you with this job.
The next step is simple. Execute./configure. here you only need to configure your extension, so what you need to do is as follows:
$ ./configure --enable-sample
Note that enable-debug and enable-maintainer-zts are not used here. this is because phpize has taken their values from the main php build and applied them to your extension. /configure script in.
Now, build it! Like any other package, you only need to type make, and the generated script file will process the remaining tasks.
After the build process is complete, you will get a message indicating that sample. so has been compiled and placed in the Next Directory named "modules" in the current build directory.
Build on windows
The translator is not familiar with the windows platform, so he skipped it.
Load built extensions as shared modules
In order for php to find this module during the request, you need to put it in php. under the Directory set by extension_dir in ini. default php. put ini in/usr/local/lib/php. ini; however, this default value may vary with the package management system. check the php-I output to see where your configuration file is.
If php. this setting in ini has not been modified, and its default value is "PHP_HOME/lib/php/extensions/debug-zts-20100525", followed by the debug-zts-20100525 is whether to enable debugging, whether to enable zts, PHPAPI No. if you have not loaded the extension, or except sample. so there are no other extensions. you can modify this value to the path of the make generate module. otherwise, the generated sample is directly generated. so copy to the directory of this setting. (: php-I | grep extension_dir find your extension_dir settings)
After the extension_dir points to the correct position, there are two ways to tell php to load your module. The first is to use the dl () function in the script:
If the script does not show that the sample has been loaded, it indicates a problem. view the preceding error message as a clue, or. for more information, see error_log.
The second method is also a more common method, in php. in ini, use the extension command to specify the module to be loaded. this command is available in php. ini settings are special and can be used multiple times with different values. so if you are already in php. ini sets an extension. instead of enumerating the same line using separators, insert a new row: extension = sample. so. your php. ini looks like this:
extension_dir=/usr/local/lib/php/modules/ extension=sample.so
Now you can run the same script without using dl (), or directly execute the php-m command, you can see the sample in the list of loaded modules.
All the code remaining in this chapter and subsequent sections assumes that you have loaded the current extension according to the method described here. if you plan to use dl (), check that the loaded code (dl () is added to the test script ()).
Static build
In the list of loaded modules, you may have noticed that some of them are in php. ini does not use the modules included in the extension command. these modules are directly built into php and are compiled into php as part of the main php program.
Static build under * nix
Now, if you enter the root directory of the php source code tree, run. /configure -- help, you will see that although your extension and all other modules are under the ext/directory, it is not listed as an option. this is because, at the moment ,. the/configure script has been generated, but your extension does not know. to be regenerated. /configure and let it find your new extension. all you need to do is execute a command:
$ ./buildconf
If you use the php version of the product release for development, you will find that. /buildconf cannot work on its own. in this case, you need to execute :. /buildconf -- force to bypass the pair. /configure command protection.
Now you execute. /configure -- help, you can see that -- enable-sample is an available option. in this case, you can execute it again. /configure: Use all the options you used to build the main php, plus -- enable-sample. in this way, the constructed php binary file is complete and contains your own extended program.
Of course, it is still a little early to do this. in addition to space occupation, you should also do some things.
Static build in windows
The translator is not familiar with the windows environment, so he skipped it.
Function
The quickest link between the user space and the extension code is PHP_FUNCTION (). First, add the following code after # include "php_sample.h" at the top of your sample. c file:
PHP_FUNCTION(sample_hello_world) { php_printf("Hello World!\n"); }
PHP_FUNCTION () macro function is like a normal C function definition, because it is expanded as follows:
#define PHP_FUNCTION(name) \ void zif_##name(INTERNAL_FUNCTION_PARAMETERS)
In this case, it is equivalent:
void zif_sample_hello_world(zval *return_value, char return_value_used, zval *this_ptr TSRMLS_DC)
Of course, defining a function is not enough. the engine needs to know the function address and the function name that should be exposed to the user space. this is done through the next code block. you need to add it after the PHP_FUNCTION () block:
static function_entry php_sample_functions[] = { PHP_FE(sample_hello_world, NULL) { NULL, NULL, NULL } };
The php_sample_functions vector is a simple NULL end vector that will become larger as you add functionality to the extension. every function you want to expose must be described in this vector. expand the PHP_FE () macro, as shown below:
{ "sample_hello_world", zif_sample_hello_world, NULL},
This provides the name of the new function and the pointer to its implementation function. here, the third parameter is used to provide implied information. for example, some parameters need to be referenced to pass values. in chapter 7th "accept parameters", you will see this feature.
Now you have a list of functions to be exposed, but they are still not connected to the engine. this is done through the sample. the last modification of c is complete. replace the NULL and/* Functions */line in your sample_module_entry struct with php_sample_functions (ensure that the comma is left ).
Now, you can rebuild the code using the-r option of the php command line for testing.-r allows you to run simple code snippets directly on the command line without creating files:
$ php -r 'sample_hello_world();
If everything is OK, you will see the output "Hello World! ". Congratulations !!!
Zend internal functions
The internal function name prefix "zif _" is the naming standard of "Zend internal function", which is used to avoid possible symbol conflicts. for example, the strlen () function of the user space is not implemented as void strlen (INTERNAL_FUNCTION_PARAMETERS) because it will conflict with the strlen of the C library.
Zif _ prefixes cannot completely avoid name conflicts. therefore, php provides a macro that can define internal functions using any name: PHP_NAMED_FUNCTION (); for example, PHP_NAMED_FUNCTION (zif_sample_hello_world) is equivalent to the previously used PHP_FUNCTION (sample_hello_world)
When PHP_NAMED_FUNCTION is used to define the implementation, the PHP_NAMED_FE () macro can be used in the function_entry vector. therefore, if you define your function PHP_NAMED_FUNCTION (purplefunc), you need to use PHP_NAMED_FE (sample_hello_world, purplefunc, NULL) instead of PHP_FE (sample_hello_world, NULL ).
In ext/standard/file. check the implementation of the fopen () function in c. It is actually defined using PHP_NAMED_FUNCTION (php_if_fopen. from the perspective of user space, it does not care about what a function is, but simply calls fopen ().
Function alias
Sometimes a function may have more than one name. in retrospect, the internal definition of a common function is that the user space function name is prefixed with zif _. we can see that the PHP_NAMED_FE () macro can easily create this optional ING.
PHP_FE(sample_hello_world, NULL) PHP_NAMED_FE(sample_hi, zif_sample_hello_world, NULL)
The PHP_FE () macro associates the zif_sample_hello_world derived from the user space function names sample_hello_world and PHP_FUNCTION (sample_hello_world. the PHP_NAMED_FE () macro associates the user space function name sample_hi with the same internal implementation.
Now, assume that the Zend Engine has undergone a major change, and the internal function prefix is changed from zif _ to pif. at this time, your extension will not work, because when PHP_NAMED_FE () is reached, zif_sample_hello_world is not defined.
This situation is not common, but it is very troublesome. you can use the PHP_FNAME () macro to expand sample_hello_world to avoid this problem:
PHP_NAMED_FE(sample_hi, PHP_FNAME(sample_hello_world), NULL)
In this case, even if the function prefix is modified, the extended zend_function_entry will be automatically updated using the macro extension.
Now you can do this, but we don't need to do it anymore. php exposes another Macro, which is specially designed to create a function alias. the previous example can be rewritten as follows:
PHP_FALIAS(sample_hi, sample_hello_world, NULL)
In fact, this is the official method to create a function alias. you will often see it in the php source code tree.
Summary
In this chapter, you have created a simple and workable php extension and learned the steps required to build it on the main platform. in the subsequent sections, you will continue to enrich this extension to include all the features of php.
The php source code tree and the tools on which it is compiled/built on various platforms often change. if some of the tools described in this chapter cannot work normally, please refer to the Installation of the php.net online manual, view the special requirements of your version.
The above is the [Translation] [php extension development and embedded] Chapter 5th-your first extension content. For more information, see PHP Chinese network (www.php1.cn )!