Home >Backend Development >PHP Tutorial >PHP Extension Writing(Sara Golemon)_PHP Tutorial

PHP Extension Writing(Sara Golemon)_PHP Tutorial

WBOY
WBOYOriginal
2016-07-13 10:38:02922browse

Original text: http://devzone.zend.com/public/view/tag/ExtensionPart I: Introduction to PHP and Zend Writing extensions I - Getting started with PHP and Zend http://devzone.zend.com/article/1021 -Extension-Writing-Part-I-Introduction-to-PHP-and-ZendPart II: Parameters, Arrays, and ZVALs -Writing-Part-II-Parameters-Arrays-and-ZVALsPart II: Parameters, Arrays, and ZVALs [continued]Writing Extension_II - Parameters, Arrays, and ZVALs[continued]http://devzone.zend.com/article/ 1023-Extension-Writing-Part-II-Parameters-Arrays-and-ZVALs-continuedPart III: Resources Writing Extension_III - Resources http://devzone.zend.com/article/1024-Extension-Writing-Part-III- Resources
Writing Extensions I: Getting Started with PHP and Zend Extensions Tutorial by Sara Golemon | Monday, February 28, 2005
Introduction What are extensions? Lifecycle Memory allocation Set up the build environment Hello World Build your extension Initial setup (INI) Global value Initial setup (INI) as a global value Check (code) Integrity What's next?
Introduction Since you are reading this tutorial, you may be interested in writing extensions to the PHP language. If it wasn't...well, maybe you didn't know about this interest, you'll find out by the time we wrap up. This tutorial assumes you have basic familiarity with the PHP language and the language in which its interpreter is implemented: C. Let's start by specifying why you want to write a PHP extension. Limited by the level of abstraction of the PHP language itself, it cannot directly access certain libraries or operating system-specific calls. You want to customize the behavior of PHP in some unusual way. You have some existing PHP code, but you know it can be faster, smaller, and consume less memory. You have some nice code for sale, the buyer can use it, but importantly cannot see the source code. These are all very valid reasons, but before creating an extension, you need to first understand what an extension is? What is an extension? If you've used PHP, you've definitely used extensions. With few exceptions, every userspace function is organized in a different extension. Many of these functions become standard extensions - more than 400 in total. PHP itself comes with 86 extensions (when the original text was written - translation annotation), each containing an average of about 30 functions. There are approximately 2500 functions for mathematical operations. As if this were not enough, the PECL repository additionally provides over 100 extensions, and many more can be found on the Internet. "What else but functions in extensions?" I hear you ask. "What's inside the extension? What is the 'core' of PHP?" The core of PHP consists of two parts. The bottom layer is Zend Engine (ZE). ZE parses human-readable scripts into machine-readable symbols and then executes these symbols within the process space. ZE also handles memory management, variable scoping, and scheduler calls. The other part is the PHP kernel, which binds the SAPI layer (Server Application Programming Interface, usually involving the host environment, such as Apache, IIS, CLI, CGI, etc.) and handles communication with it. It also provides a consistent control layer for safe_mode and open_basedir detection, just like the flow layer connects user space functions such as fopen(), fread(), and fwrite() to file and network I/O. Lifecycle When a given SAPI starts, for example in response to /usr/local/apache/bin/apachectl start, PHP begins by initializing its kernel subsystem. Near the end of the startup routine, it loads each extension's code and calls its module initialization routine (MINIT). This allows each extension to initialize internal variables, allocate resources, register resource handlers, and register its own functions with ZE so that ZE knows what code to execute when the script calls the functions. Next, PHP waits for the SAPI layer to request the page to be processed. For SAPIs like CGI or CLI, this will happen immediately and only once. For Apache, IIS or other mature web server SAPI, this will happen every time the remote user requests the page, so it will be repeated many times, possibly concurrently. Regardless of how the request is generated, PHP begins by asking ZE to set up the script's runtime environment and then calls each extension's request initialization (RINIT) function. RINIT gives extensions the opportunity to set specific environment variables, allocate resources upon request, or perform other tasks such as auditing. There is a typical example of the role of RINIT in session extension. If the session.auto_start option is enabled, RINIT will automatically trigger the session_start() function in user space and the preassembled $_SESSION variable. Once the request is initiated, ZE takes over control, translating the PHP script into symbols and eventually opcodes and running them step by step. If any opcode needs to call an extended function, ZE will bind the parameters to the function and temporarily relinquish control until the function completes. After the script runs, PHP calls the request shutdown (RSHUTDOWN) function of each extension to perform final cleanup work (such as saving session variables to disk). Next, ZE performs a cleanup process (garbage collection) - effectively unset()ing every variable used during the previous request. Once completed, PHP continues to wait for other document requests from SAPI or a shutdown signal. For SAPIs like CGI and CLI, there is no "next request", so the SAPI starts shutting down immediately.During shutdown, PHP again iterates through each extension, calls its module shutdown (MSHUTDOWN) function, and eventually shuts down its own kernel subsystem. This process may sound daunting at first, but once you get down to a working extension, you'll gradually start to understand it. Memory Allocation To prevent poorly written extensions from losing memory, ZE uses additional flags to implement its own internal memory manager to indicate persistence. Durable allocated memory is meant to last longer than a single request. In contrast, non-persistent allocations during a request will be released at the end of the request regardless of whether the release (memory) function is called. For example, userspace variables are allocated as non-persistent because they are no longer useful after the request ends. However, in theory, an extension could rely on ZE to automatically release non-persistent memory at the end of a page request, but this is not recommended. Because the allocated memory will remain unreclaimed for a long time, the resources associated with it may not be closed properly, and it is a bad habit to eat without wiping your mouth. You'll discover later that it's actually quite easy to ensure that all allocated data is properly cleaned. Let's briefly compare traditional memory allocation functions (which should only be used in external libraries) with PHP/ZE's persistent and non-persistent memory allocation functions. Traditional non-persistent persistent malloc(count)calloc(count, num) emalloc(count)ecalloc(count, num) pemalloc(count, 1)*pecalloc(count, num, 1) strdup(str)strndup(str, len) estrdup(str)estrndup(str, len) pestrdup(str, 1)pemalloc() & memcpy() free(ptr) efree(ptr) pefree(ptr, 1)realloc(ptr, newsize) erealloc(ptr, newsize) ) perealloc(ptr, newsize, 1)malloc(count * num + extr)** safe_emalloc(count, num, extr) safe_pemalloc(count, num, extr)* The pemalloc() family contains a 'persistent' flag to allow them to implement The functionality of the corresponding non-persistent function. For example: emalloc(1234) is the same as pemalloc(1234, 0). ** safe_emalloc() and (in PHP 5) safe_pemalloc() perform additional checks to prevent integer overflow.
Setting up the build environment Now that you've learned a bit about the inner workings of PHP and the Zend Engine, I bet you want to dig in and start building something. Before doing this, you need to gather some necessary build tools and set up an environment suitable for your purposes. First, you need PHP itself and the set of build tools it requires. If you're new to building PHP from source, I recommend you take a look at http://www.php.net/install.unix. (Developing PHP extensions for Windows will be covered in a future article). However, using binary distributions of PHP is a bit risky, and these versions tend to ignore two important options of ./configure that come in handy during development. The first --enable-debug. This option will compile additional symbol information into the PHP executable file, so that if a segfault occurs, you can get a core dump file from it and use gdb to trace and find where and why the segfault occurred. Another option depends on your PHP version. This option is named --enable-experimental-zts in PHP 4.3 and --enable-maintainer-zts in PHP 5 and later versions. This option makes PHP think it is running in a multi-threaded environment and allows you to catch common program errors that are harmless in a non-multi-threaded environment, but makes your extension unsafe for use in a multi-threaded environment. Once you have compiled PHP with these additional options and installed it on your development server (or workstation), you can add your first extension to it. Hello World What programming introduction can completely ignore the required Hello World program? In this example, the extension you will make exports a simple function that returns a string containing "Hello World". With PHP you might do this: Now you will transfer this into a PHP extension. First, we create a directory named hello in the directory ext/ of your PHP source tree and chdir into the directory. In fact, this directory could be placed anywhere within or outside the PHP source tree, but I want you to put it here to illustrate an unrelated concept that will appear in future articles. You need to create 3 files here: the source file containing the hello_world function, the header file containing references that PHP will use to load your extension, and the configuration file that phpize will use to prepare your extension for compilation.config.m4PHP_ARG_ENABLE(hello, whether to enable Hello World support,[ --enable-hello   Enable Hello World support])if test "$PHP_HELLO" = "yes"; then  AC_DEFINE(HAVE_HELLO, 1, [Whether you have Hello World])  PHP_NEW_EXTENSION(hello, hello.c, $ext_shared)fi php_hello.h#ifndef PHP_HELLO_H#define PHP_HELLO_H 1#define PHP_HELLO_WORLD_VERSION "1.0"#define PHP_HELLO_WORLD_EXTNAME "hello"PHP_FUNCTION(hello_world);extern zend_module_entry hello_module_entry;#define phpext_hello_ptr &hello_module_entry#endif hello.c#ifdef HAVE_CONFIG_H#include "config.h"#endif#include "php.h"#include "php_hello.h"static function_entry hello_functions[] = {PHP_FE(hello_world, NULL){NULL, NULL, NULL}};zend_module_entry hello_module_entry = {#if ZEND_MODULE_API_NO >= 20010901STANDARD_MODULE_HEADER,#endifPHP_HELLO_WORLD_EXTNAME,hello_functions,NULL,NULL,NULL,NULL,NULL,#if ZEND_MODULE_API_NO >= 20010901PHP_HELLO_WORLD_VERSION,#endifSTANDARD_MODULE_PROPERTIES};#ifdef COMPILE_DL_HELLOZEND_GET_MODULE(hello)#endifPHP_FUNCTION(hello_world){RETURN_STRING("Hello World", 1);} 在上面的示例扩展中,你所看到的代码大多是黏合剂,作为将扩展引入PHP的协议语言并且在其间建立会话用于通信。只有最后四行才是你所认为“实际做事的代码”,它们负责与用户空间的脚本交互这一层次。这些代码看起来确实非常像之前看到的PHP代码,而且一看就懂:声明一个名为hello_world的函数让该函数返回字符串:“Hello World”....嗯....1? 那个1是怎么回事儿?回忆一下,ZE包含一个复杂的内存管理层,它可以确保分配的资源在脚本退出时被释放。然而,在内存管理领域,两次释放同一块内存是绝对禁止的(big no-no)。这种被称为二次释放(double freeing)的做法,是引起段错误的一个常见因素,原因是它使调用程序试图访问不再拥有的内存。类似地,你不应该让ZE去释放一个静态字符串缓冲区(如我们的示例扩展中的“Hello World”),因为它存在于程序空间,而不是被任何进程(process)拥有的数据块。RETURN_STRING()可以假定传入其中的任何字符串都需要被复制以便稍后可被安全地释放;但是由于内部的函数给字符串动态地分配内存、填充并返回并不罕见,第二参数RETURN_STRING()允许我们指定是否需要拷贝字符串的副本。要进一步说明这个概念,下面的代码片段与上面的对应版本等效:PHP_FUNCTION(hello_world){char *str;str = estrdup("Hello World");RETURN_STRING(str, 0);} 在这个版本中,你手工为最终将被传回调用脚本的字符串“Hello World”分配内存,然后把这快内存“给予”RETURN_STRING(),用第二参数0指出它不需要制作自己的副本,可以拥有我们的。构建你的扩展本练习的最后一步是将你的扩展构建为可动态加载的模块。如果你已经正确地拷贝了上面的代码,只需要在ext/hello/中运行3个命令:$ phpize$ ./configure --enable-hello$ make每个命令都运行后,可在目录ext/hello/modules/中看到文件hello.so。现在,你可像其他扩展一样把它拷贝到你的扩展目录(默认是/usr/local/lib/php/extensions/,检查你的php.ini以确认),把extension=hello.so加入你的php.ini以使PHP启动时加载它。 对于CGI/CLI,下次运行PHP就会生效;对于web服务器SAPI,如Apache,需要重新启动web服务器。我们现在从命令行尝试下:$ php -r 'echo hello_world();'如果一切正常,你会看到这个脚本输出的Hello World,因为你的已加载的扩展中的函数hello_world()返回这个字符串,而且echo命令原样输出传给它的内容(本例中是函数的结果)。可以同样的方式返回其他标量,整数值用RETURN_LONG(),浮点值用 RETURN_DOUBLE(),true/false值用RETURN_BOOL(),RETURN_NULL()?你猜对了,是NULL。我们看下它们各自在实例中的应用,通过在文件hello.c中的function_entry结构中添加对应的几行PHP_FE(),并且在文件结尾添加一些PHP_FUNCTION()。static function_entry hello_functions[] = {PHP_FE(hello_world, NULL)PHP_FE(hello_long, NULL)PHP_FE(hello_double, NULL)PHP_FE(hello_bool, NULL)PHP_FE(hello_null, NULL){NULL, NULL, NULL}};PHP_FUNCTION(hello_long){RETURN_LONG(42);}PHP_FUNCTION(hello_double){RETURN_DOUBLE(3.1415926535);}PHP_FUNCTION(hello_bool){RETURN_BOOL(1);}PHP_FUNCTION(hello_null){RETURN_NULL();} 你也需要在头文件php_hello.h中函数hello_world()的原型声明旁边加入这些函数的原型声明,以便构建进程正确进行:PHP_FUNCTION(hello_world);PHP_FUNCTION(hello_long);PHP_FUNCTION(hello_double);PHP_FUNCTION(hello_bool);PHP_FUNCTION(hello_null); 由于你没有改变文件config.m4,这次跳过phpize和./configure步骤直接跳到make在技术上是安全的。However, at this point I want you to go through the entire build steps again to make sure it builds well. Also, you should call make clean all instead of simply making in the last step to ensure that all source files are rebuilt. Again, so far, these (steps) are not necessary depending on the type of changes you make, but it's better to be safe than confused. Once the module is built, copy it to your extensions directory again, replacing the old version. At this point you can call the PHP interpreter again and simply pass in the script to test the newly added function. In fact, why not do it now? I'll wait here...done? OK If you use var_dump() instead of echo to view the output of each function, you may notice that hello_bool() returns true. That is the result represented by the value 1 in RETURN_BOOL(). As in PHP scripts, the integer value 0 is equal to FALSE, and other integers are equal to TRUE. Just as a convention, extension authors usually use 1, and you are encouraged to do the same, but don't feel restricted by it. For additional readability purposes, the macros RETURN_TRUE and RETURN_FALSE can also be used; another hello_bool(), this time using RETURN_TRUE: PHP_FUNCTION(hello_bool){RETURN_TRUE;} Note that there are no parentheses here. In that case, RETURN_TRUE and RETURN_FALSE are aberrations compared to the other RETURN_*() macros, so be sure not to get caught by this one. You may have noticed that in each of the above examples, we did not pass in 0 or 1 to indicate whether to copy. This is because, for simple small scalars like these, no additional memory needs to be allocated or freed (other than the variable container itself - which we will look at in more depth in Part 2). There are three other return types: Resource ( Like the names of the values ​​returned by mysql_connect(), fsockopen() and ftp_connect(), but not limited to these), arrays (also known as HASH) and objects (returned by the keyword new). We'll see them in Part 2 when we explain variables in depth. Initial Setup (INI) Zend Engine provides two ways to manage INI values. Let's look at the simpler ones now, and then explore more sophisticated but also more complex ways when you deal with global data. Suppose you want to define a value in php.ini for your extension, hello.greeting, which holds the greeting string that will be used in the hello_world() function. You need to add some code to hello.c and php_hello.h, and make some key changes to the hello_module_entry structure. First add the following prototype in the file php_hello.h near the prototype declaration of the user space function: PHP_MINIT_FUNCTION(hello);PHP_MSHUTDOWN_FUNCTION(hello);PHP_FUNCTION(hello_world);PHP_FUNCTION(hello_long);PHP_FUNCTION(hello_double);PHP_FUNCTION(hello_bool);PHP_FUNCTION (hello_null); Now go to the file hello.c, remove the current version of hello_module_entry, and replace it with the following list: zend_module_entry hello_module_entry = {#if ZEND_MODULE_API_NO >= 20010901STANDARD_MODULE_HEADER,#endifPHP_HELLO_WORLD_EXTNAME,hello_functions,PHP_MINIT (hello),PHP_MSHUTDOWN(hello) ,NULL,NULL,NULL,#if ZEND_MODULE_API_NO >= 20010901PHP_HELLO_WORLD_VERSION,#endifSTANDARD_MODULE_PROPERTIES};PHP_INI_BEGIN()PHP_INI_ENTRY("hello.greeting", "Hello World", PHP_INI_ALL, NULL)PHP_INI_END() PHP_MINIT_FUNCTION(hello){REGISTER_INI_ENTRIES() ;return SUCCESS;}PHP_MSHUTDOWN_FUNCTION(hello){UNREGISTER_INI_ENTRIES();return SUCCESS;} Now, you just need to add an #include next to those #includes at the top of the file hello.c, so that you can get the correct INI-capable header file: #ifdef HAVE_CONFIG_H#include "config.h"#endif#include "php.h"#include "php_ini.h"#include "php_hello.h" Finally, you can modify the function hello_world to use the value of INI: PHP_FUNCTION(hello_world ){RETURN_STRING(INI_STR("hello.greeting"), 1);} Note that you will want to copy the value returned from INI_STR(). This is because, as far as the PHP variable stack is concerned, it is a static string. In fact, if you try to modify the returned string, the PHP execution environment will become unstable or even crash. The first change in this section introduces two very familiar functions: MINIT and MSHUTDOWN. As mentioned earlier, these methods are each called during initial startup and final shutdown of SAPI. They are not called during or between requests. In this case they are used to register the entries defined in your extension with php.ini. Later in this series of tutorials, you will also see how to use the MINIT and MSHUTDOWN functions to register resources, objects, and stream processors. INI_STR() is used in the function hello_world() to obtain the current string value of the hello.greeting entry. Other similar functions exist for obtaining values ​​of other types, long, double and boolean, as shown in the table below; additional ORIG versions are also provided, which are provided in the php.ini file. The INI (original) setting (before being changed by the .htaccess or ini_set() directive) provides the value of the referenced INI setting as it was set in php.ini - Translation Note).Current value primitive value type INI_STR(name) INI_ORIG_STR(name) char * (NULL terminated)INI_INT(name) INI_ORIG_INT(name) signed longINI_FLT(name) INI_ORIG_FLT(name) signed doubleINI_BOOL(name) INI_ORIG_BOOL(name) zend_bool passed in PHP_INI_ENTRY( ) contains the name string used in the php.ini file. To avoid namespace conflicts, you should use the same convention as for functions, that is, prefix all values ​​with the name of your extension, just like you did with hello.greeting. As a matter of convention only, a period is used to separate the extension's name from the more descriptive initializer name. The second parameter is the initial value (default value?-Annotation), and whether it is a numeric value or not, it must be a string of type char*. This is mainly based on the fact that the original value in the .ini file is text - along with everything else it is stored as a text file. The INI_INT(), INI_FLT() or INI_BOOL() you use in subsequent scripts will undergo type conversion. The third value passed in is the access mode modifier. This is a bitmask field that determines when and where this INI value is modifiable. For some of them, like register_globals, it just doesn't allow changing the value with ini_set() in a script, since the setting only makes sense during request startup (before the script can run). Others, such as allow_url_fopen, are administrative settings that you won't want users of a shared hosting environment to modify, whether through ini_set() or .htaccess directives. A typical value for this parameter might be PHP_INI_ALL, indicating that the value can be modified anywhere. Then there is PHP_INI_SYSTEM|PHP_INI_PERDIR, indicating that this setting can be modified in the php.ini file or through the Apache directive in the .htaccess file, but cannot be modified with ini_set(). Alternatively, PHP_INI_SYSTEM can be used, indicating that the value can only be modified in the php.ini file and not anywhere else. We'll ignore the fourth parameter for now, except to mention that it allows a method callback to be triggered when the initial settings are changed - for example using ini_set(). This allows the extension to perform more precise control when settings change, or to trigger an associated behavior based on the new settings. Global value expansion often requires tracking a value throughout a particular request and keeping it separate from other requests that may be occurring at the same time. In non-multithreaded SAPI it's simple: just declare a global variable in the source file and access it when needed. The problem is that since PHP is designed to run in multi-threaded web servers (such as Apache 2 and IIS), it needs to keep the global values ​​used by each thread independent. PHP greatly simplifies this by using the TSRM (Thread Safe Resource Management, thread-safe resource manager) abstraction layer - sometimes called ZTS (Zend Thread Safety, Zend thread safety). In fact, you have already used part of TSRM at this point, but you just didn't realize it. (Don't look too hard; you'll see it everywhere as this series progresses.) As with any global scope, the first step in creating a thread-safe scope is to declare it. For the purpose of this example, you will declare a long global value with a value of 0. Each time hello_long() is called, the value is incremented by 1 and returned. Add the following code segment after the #define PHP_HELLO_H statement in the php_hello.h file: #ifdef ZTS#include "TSRM.h"#endifZEND_BEGIN_MODULE_GLOBALS(hello)long counter;ZEND_END_MODULE_GLOBALS(hello)#ifdef ZTS#define HELLO_G(v) TSRMG (hello_globals_id, zend_hello_globals *, v)#else#define HELLO_G(v) (hello_globals.v)#endif The RINIT method will also be used this time, so you need to declare its prototype in the header file: PHP_MINIT_FUNCTION(hello);PHP_MSHUTDOWN_FUNCTION( hello);PHP_RINIT_FUNCTION(hello); Now we go back to the file hello.c and add the following code immediately after the include code block: #ifdef HAVE_CONFIG_H#include "config.h"#endif#include "php.h"#include "php_ini.h"#include "php_hello.h"ZEND_DECLARE_MODULE_GLOBALS(hello) Change hello_module_entry and add PHP_RINIT(hello): zend_module_entry hello_module_entry = {#if ZEND_MODULE_API_NO >= 20010901STANDARD_MODULE_HEADER,#endifPHP_H ELLO_WORLD_EXTNAME,hello_functions,PHP_MINIT(hello),PHP_MSHUTDOWN(hello : s *hello_globals) {} php_rinit_function (hello) {hello_g (counter) = 0; Return Success;} php_minit_function (hello) {ZEND_INIT_GLOBALOBAL S (hello, php_hello_init_globals, null); register_ini_entries (); Return success;} Finally, you can modify hello_long ( ) function uses this value: PHP_FUNCTION(hello_long){HELLO_G(counter)++;RETURN_LONG(HELLO_G(counter));} In the code you added to php_hello.h, you used two macros - ZEND_BEGIN_MODULE_GLOBALS() and ZEND_END_MODULE_GLOBALS( ) - used to create a structure named zend_hello_globals, which contains a long variable.Then conditionally define HELLO_G() to get the value from the thread pool, or from the global scope if you are compiling for a non-multithreaded environment. In hello.c, you use the ZEND_DECLARE_MODULE_GLOBALS() macro to instantiate the zend_hello_globals structure, which is either truly global (if the build is not thread-safe) or a member of this thread's resource pool. As extension authors, we don't need to worry about the difference because the Zend engine takes care of this for us. Finally, you use ZEND_INIT_MODULE_GLOBALS() in MINIT to allocate a thread-safe resource id—don't worry about what it is yet. You may have noticed that php_hello_init_globals() actually does nothing but declares RINIT to initialize the variable counter to 0. Why? The key is when these two functions are called. php_hello_init_globals() is only called when starting a new process or thread; however, each process can handle multiple requests, so initializing the variable counter to 0 with this function will only run on the first page request. Subsequent page requests to the same process will still get the value of the counter variable previously stored here, and therefore will not start counting from 0. To initialize the counter variable to 0 for each page request, we implement the RINIT function, which, as seen before, is called before each page request. We include the php_hello_init_globals() function at this point because you will need it later, and passing NULL for this initialization function in ZEND_INIT_MODULE_GLOBALS() will cause a segfault on non-multithreaded platforms. Initial settings (INI) as global values ​​Recall that a php.ini value declared with PHP_INI_ENTRY() is parsed as a string and converted to other formats as needed using INI_INT(), INI_FLT(), and INI_BOOL(). For some settings, doing this causes a lot of unnecessary duplication of work when reading these values ​​during the execution of the script. Fortunately, you can have ZE store the INI value as a specific data type and perform the type conversion only when its value is changed. Let's try it out by declaring another INI value, this time a boolean indicating whether the variable counter is incrementing or decrementing. To get started, change the MODULE_GLOBALS block in php_hello.h to the following code: ZEND_BEGIN_MODULE_GLOBALS(hello)long counter;zend_bool direction;ZEND_END_MODULE_GLOBALS(hello) Next, modify the PHP_INI_BEGIN() block to declare the INI value, like this: PHP_INI_BEGIN( )PHP_INI_ENTRY("hello.greeting", "Hello World", PHP_INI_ALL, NULL)STD_PHP_INI_ENTRY("hello.direction", "1", PHP_INI_ALL, OnUpdateBool, direction, zend_hello_globals, hello_globals)PHP_INI_END() Now initialize init_globals with the following code Settings in the method: static void php_hello_init_globals(zend_hello_globals *hello_globals){hello_globals->direction = 1;} And finally, apply this initial setting in hello_long() to decide whether to increment or decrement: PHP_FUNCTION(hello_long){if (HELLO_G(direction)) {HELLO_G(counter)++;} else {HELLO_G(counter)--;}RETURN_LONG(HELLO_G(counter));} That’s it. The OnUpdateBool method specified in the INI_ENTRY section will automatically convert the values ​​provided via ini_set() in php.ini, .htaccess, or scripts to the appropriate TRUE/FALSE values ​​so that you can access them directly in the script. The last three parameters of STD_PHP_INI_ENTRY tell PHP which global variables to change, what the structure of our extended global (scope) looks like, and what the name of the global scope that holds these variables is. Checking (Code) Completeness Our three files so far should look something like the list below. (Some items have been moved and reorganized for readability.)config.m4PHP_ARG_ENABLE(hello, whether to enable Hello World support,[ --enable-hello   Enable Hello World support])if test "$PHP_HELLO" = "yes"; then  AC_DEFINE(HAVE_HELLO, 1, [Whether you have Hello World])  PHP_NEW_EXTENSION(hello, hello.c, $ext_shared)fi php_hello.h#ifndef PHP_HELLO_H#define PHP_HELLO_H 1#ifdef ZTS#include "TSRM.h"#endifZEND_BEGIN_MODULE_GLOBALS(hello)long counter;zend_bool direction;ZEND_END_MODULE_GLOBALS(hello)#ifdef ZTS#define HELLO_G(v) TSRMG(hello_globals_id, zend_hello_globals *, v)#else#define HELLO_G(v) (hello_globals.v)#endif#define PHP_HELLO_WORLD_VERSION "1.0"#define PHP_HELLO_WORLD_EXTNAME "hello"PHP_MINIT_FUNCTION(hello);PHP_MSHUTDOWN_FUNCTION(hello);PHP_RINIT_FUNCTION(hello);PHP_FUNCTION(hello_world);PHP_FUNCTION(hello_long);PHP_FUNCTION(hello_double);PHP_FUNCTION(hello_bool);PHP_FUNCTION(hello_null);extern zend_module_entry hello_module_entry;#define phpext_hello_ptr &hello_module_entry#endif hello.c#ifdef HAVE_CONFIG_H#include "config.h"#endif#include "php.h"#include "php_ini.h"#include "php_hello.h"ZEND_DECLARE_MODULE_GLOBALS(hello)static function_entry hello_functions[] = {PHP_FE(hello_world, NULL)PHP_FE(hello_long, NULL)PHP_FE(hello_double, NULL)PHP_FE(hello_bool, NULL)PHP_FE(hello_null, NULL){NULL, NULL, NULL}};zend_module_entry hello_module_entry = {#if ZEND_MODULE_API_NO >= 20010901STANDARD_MODULE_HEADER,#endifPHP_HELLO_WORLD_EXTNAME,hello_functions,PHP_MINIT(hello),PHP_MSHUTDOWN(hello),PHP_RINIT(hello),NULL,NULL,#if ZEND_MODULE_API_NO >= 20010901PHP_HELLO_WORLD_VERSION,#endifSTANDARD_MODULE_PROPERTIES};#ifdef COMPILE_DL_HELLOZEND_GET_MODULE(hello)#endifPHP_INI_BEGIN()PHP_INI_ENTRY("hello.greeting", "Hello World", PHP_INI_ALL, NULL)STD_PHP_INI_ENTRY("hello.direction", "1", PHP_INI_ALL, OnUpdateBool, direction, zend_hello_globals, hello_globals)PHP_INI_END()static void php_hello_init_globals(zend_hello_globals *hello_globals){hello_globals->direction = 1;}PHP_RINIT_FUNCTION(hello){HELLO_G(counter) = 0;return SUCCESS;}PHP_MINIT_FUNCTION(hello){ZEND_INIT_MODULE_GLOBALS(hello, php_hello_init_globals, NULL);REGISTER_INI_ENTRIES();return SUCCESS;}PHP_MSHUTDOWN_FUNCTION(hello){UNREGISTER_INI_ENTRIES();return SUCCESS;}PHP_FUNCTION(hello_world){RETURN_STRING("Hello World", 1);}PHP_FUNCTION(hello_long){if (HELLO_G(direction)) {HELLO_G(counter)++;} else {HELLO_G(counter)--;}RETURN_LONG(HELLO_G(counter));}PHP_FUNCTION(hello_double){RETURN_DOUBLE(3.1415926535);}PHP_FUNCTION(hello_bool){RETURN_BOOL(1);}PHP_FUNCTION(hello_null){RETURN_NULL();} 
下一步是什么?本教程探究了一个简单PHP扩展的结构,包括导出函数、返回值、声明初始设置(INI)以及在(客户端)请求期间跟踪其内部状态。下一部分,我们将探究PHP变量的内部结构,以及在脚本环境中如何存储、跟踪和维护它们。在函数被调用时,我们将使用zend_parse_parameters接收来自于程序的参数,以及探究如何返回更加复杂的结果,包括数组、对象和本教程提到的资源等类型。

www.bkjia.comtruehttp://www.bkjia.com/PHPjc/735137.htmlTechArticle原文:http://devzone.zend.com/public/view/tag/ExtensionPart I: Introduction to PHP and Zend编写扩展I - PHP和Zend起步http://devzone.zend.com/article/1021-Extension-Writing-...
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn