", get_active_function_name(TSRMLS_C)); zend_printf(”The file currently executed is %s
”, zend_get_executed_filename(TSRMLS_C)); zend_printf(”The current line being executed is %i
”, zend_get_executed_lineno(TSRMLS_C)); 启动函数和关闭函数会在模块的(载入时)初始化和(卸载时)反初始化时被调用,而且只调用这一次。 正如我们在本章前面(见 Zend 模块描述块的说明)所提到的,它们是模块和请求启动和关闭时所发生的 事件。 模块启动/关闭函数会在模块加载和卸载时被调用。请求启动/关闭函数会在每次处理一个请求时(也就是 在执行一个脚本文件时)被调用。 对于动态加载的扩展而言,模块和请求的启动函数与模块和请求的关闭函数都是同时发生的(严格来说模 块启动函数是先于请求启动函数被调用的,译注)。 可以用某些宏来声明和实现这些函数,详情请参阅前面的关于“Zend 模块声明”的讨论。 PHP 还允许你在你的模块里面调用一些一些用户定义的函数,这样在实现某些回调机制(比如在做一些数 组的轮循(array walking)、搜索或设计一些简单的事件驱动的程序时)时会很方便。 我们可以通过调用 call_user_function_ex() 来调用用户函数。它需要你即将访问函数表的指针、这个 对象的指针(假如你访问的是类的一个方法的话),函数名、返回值、参数个数、具体的参数数组和一个 是否需要进行 zval 分离的标识(这个函数原型已经“过时”了,至少是从 PHP 4.2 开始这个函数就追加了 更多电子书教程下载请登陆http://down.zzbaike.com/ebook 本站提供的电子书教程均为网上搜集,如果该教程涉及或侵害到您的版权请联系我们。 一个 HashTable *symbol_table 参数。下面所列举的函数原型更像是 call_user_function () 的声明。 译注)。 ZEND_API int call_user_function_ex(HashTable *function_table, zval *object, zval *function_name, zval **retval_ptr_ptr, int param_count, zval **params[], int no_separation); 需要注意的是你不必同时指定 function_table 和 object 这两个参数,只需要指定其中一个就行了。不过 如果你想调用一个方法的话,那你就必须提供一个包含此方法的对象。这时 call_user_function() 会 自动将函数表设置为当前这个对象的函数表。而对于其他情况,只需要设定一下 function_table 而把 object 设为 NULL 就行了。 一般情况下,默认的函数表是包含有所有函数的“根”函数表。这个函数表是编译器全局变量的一部分,你 可以通过 CG() 宏来访问它。如果想把编译器全局变量引入你的函数,只需先执行一下 TSRMLS_FETCH 宏就可以了。 而调用的函数名是保存在一个 zval 容器内的。猛一下你可能会感到好奇,但其实这是很合乎逻辑的。想 想看,既然我们在脚本中的大部分时间都是在接收一个函数名作为参数,并且这个参数还是被转换成(或 被包含在)一个 zval 容器。那还不如现在就直接把这个 zval 容器传送给函数,只是这个 zval 容器的类 型必须为 IS_STRING。 下一个参数是返回值 return_value 的指针。这个容器的空间函数会自动帮你申请,所以我们无需手动申 请,但在事后这个容器空间的销毁释放工作得由我们自己(使用 zval_dtor())来做。 跟在 return_value 后面的是一个标识参数个数的整数和一个包含具体参数的数组。最后一个参数 no_separation 指明了函数是否禁止进行 zval 分离操作。这个参数应该总是设为 0,因为如果设为 1 的 话那这个函数会节省一些空间但要是其中任何一个参数需要做 zval 分离时都会导致操作失败。 “例 3.15 调用用户函数”向我们展示如何去调用一个脚本中的用户函数。这段代码调用了一个我们模块所提 供的 call_userland() 函数。模块中的 call_userland() 函数会调用脚本中一个名为它的参数的用户 函数,并且将这个用户函数的返回值直接作为自己的返回值返回脚本。另外你可能注意到了我们在最后调 用了析构函数。这个操作或许没有太大必要(因为这些值都应该是分离过的,对它们的赋值将会很安全), 但这么做总没有什么坏处,说不定在某个关键时刻它成为我们的一道“免死金牌”。:D 例 3.15 调用用户函数 zval **function_name; zval *retval; 更多电子书教程下载请登陆http://down.zzbaike.com/ebook 本站提供的电子书教程均为网上搜集,如果该教程涉及或侵害到您的版权请联系我们。 if((ZEND_NUM_ARGS() != 1) || (zend_get_parameters_ex(1, &function_name) != SUCCESS)) { WRONG_PARAM_COUNT; } if((*function_name)->type != IS_STRING) { zend_error(E_ERROR, “Function requires string argument”); } TSRMSLS_FETCH(); if(call_user_function_ex(CG(function_table), NULL, *function_name, &retval, 0, NULL, 0) != SUCCESS) { zend_error(E_ERROR, “Function call failed”); } zend_printf(”We have %i as type\n”, retval->type); *return_value = *retval; zval_copy_ctor(return_value); zval_ptr_dtor(&retval); 调用脚本: 上例将输出: We are in the test function! We have 3 as type Return value: „hello‟ PHP4 重写了对初始化文件的支持。现在你可以直接在代码中指定一些初始化选项,然后在运行时读取和 改变这些选项值,甚至还可以在选项值改变时接到相关通知。 更多电子书教程下载请登陆http://down.zzbaike.com/ebook 本站提供的电子书教程均为网上搜集,如果该教程涉及或侵害到您的版权请联系我们。 如果想要为你的模块创建一个 .ini 文件的配置节,可以使用宏 PHP_INI_BEGIN() 来标识这个节的开 始,并用 PHP_INI_END() 表示该配置节已经结束。然后在两者之间我们用 PHP_INI_ENTRY() 来创 建具体的配置项。 PHP_INI_BEGIN() PHP_INI_ENTRY(”first_ini_entry”, ”has_string_value”, PHP_INI_ALL, NULL) PHP_INI_ENTRY(”second_ini_entry”, “2″, PHP_INI_SYSTEM, OnChangeSecond) PHP_INI_ENTRY(”third_ini_entry”, ”xyz”, PHP_INI_USER, NULL) PHP_INI_END() PHP_INI_ENTRY() 总共接收 4 个参数:配置项名称、初始值、改变这些值所需的权限以及在值改变时 用于接收通知的函数句柄。配置项名称和初始值必须是一个字符串,即使它们是一个整数。 更改这些值所需的权限可以划分为三种:PHP_INI_SYSTEM 只允许在 php.ini 中改变这些值; PHP_INI_USER 允许用户在运行时通过像 .htaccess 这样的附加文件来重写其值;而 PHP_INI_ALL 则允许随意更改。其实还有第四种权限:PHP_INI_PERDIR,不过我们还暂时不能确定它有什么影响。 (本段关于这几种权限的说明与手册中《附录 G php.ini 配置选项》一节的描述略有出入。根据译者自己 查到的资料,相比之下还是《附录 G php.ini 配置选项》更为准确些。译注) 第四个参数是初始值被改变时接收通知的函数句柄。一旦某个初始值被改变,那么相应的函数就会被调用。 这个函数我们可以用宏 PHP_INI_MH 来定义: PHP_INI_MH(OnChangeSecond); // handler for ini-entry "second_ini_entry" // specify ini-entries here PHP_INI_MH(OnChangeSecond) { zend_printf(”Message caught, our ini entry has been changed to %s
”, new_value); return(SUCCESS); } 改变后的新值将会以字符串的形式并通过一个名为 new_value 变量传递给函数。要是再注意一下 PHP_INI_MH 的定义就会发现,我们实际上用到了不少参数: #define PHP_INI_MH(name) int name(php_ini_entry *entry, char *new_value, uint new_value_length, void *mh_arg1, void *mh_arg2, void *mh_arg3) 这些定义都可以在 php_ini.h 文件里找到。可以发现,我们的通知接收函数可以访问整个配置项、改变后 的新值以及它的长度和其他三个可选参数。这几个可选参数可以通过 PHP_INI_ENTRY1(携带一个附加 更多电子书教程下载请登陆http://down.zzbaike.com/ebook 本站提供的电子书教程均为网上搜集,如果该教程涉及或侵害到您的版权请联系我们。 参数)、PHP_INI_ENTRY2(携带两个附加参数)、PHP_INI_ENTRY3(携带三个附加参数)等宏来加 以指定。 关于值改变的通知函数应该被用来本地缓存一些初始花选项以便可以更快地对其访问或被用来从事一个值 发生改变时所要求完成的任务。比如要是一个模块对一个主机常量进行了连接,而这时有人改变了主机名, 那么就需要自动地关闭原来的连接,并尝试进行新的连接。 可以使用“表 3.17 PHP 中用以访问初始化配置项的宏”来访问初始化配置项: 表 3.17 PHP 中用以访问初始化配置项的宏 宏 说明 INI_INT(name) 将配置项 name 的当前值以长整数返回。 INI_FLT(name) 将配置项 name 的当前值以双精度浮点数返回。 INI_STR(name) 将配置项 name 的当前值以字符串返回。 注意:这个字符串 不是复制过的字符串,而是直接指向了内部数据。如果你需要 进行进一步的访问的话,那就需要再进行复制一下。 INI_BOOL(name) 将配置项 name 的当前值以布尔值返回。(返回值被定义为 zend_bool,也就是说是一个 unsigned char)。 INI_ORIG_INT(name) 将配置项 name 的初始值以长整型数返回。 INI_ORIG_FLT(name) 将配置项 name 的初始值以双精度浮点数返回。 INI_ORIG_STR(name) 将配置项 name 的初始值以字符串返回。 注意:这个字符串 不是复制过的字符串,而是直接指向了内部数据。如果你需要 进行进一步的访问的话,那就需要再进行复制一下。 INI_ORIG_BOOL(name) 将配置项 name 的初始值以布尔值返回。(返回值被定义为 zend_bool,也就是说是一个 unsigned char)。 最后,你还得把整个初始化配置项引入 PHP。这项工作可以在模块的起始/结束函数中使用宏 REGISTER_INI_ENTRIES() 和 UNREGISTER_INI_ENTRIES() 来搞定。 ZEND_MINIT_FUNCTION(mymodule) { REGISTER_INI_ENTRIES(); } ZEND_MSHUTDOWN_FUNCTION(mymodule) { UNREGISTER_INI_ENTRIES(); } 更多电子书教程下载请登陆http://down.zzbaike.com/ebook 本站提供的电子书教程均为网上搜集,如果该教程涉及或侵害到您的版权请联系我们。 现在你已经掌握了很多关于 PHP 的知识了。你已经知道了如何创建一个动态加载的模块或被静态连接的 扩展。你还知道了在 PHP 和 Zend 的内部变量是如何储存的,以及如何创建和访问这些变量。另外你也 知道了很多诸如输出信息文本、自动将变量引入符号表等一系列工具函数的应用。 尽管这一章常常有点“参考”的意味,但我们还是希望它能给你一些关于如何开始编写自己的扩展这方面的 知识。限于篇幅,我们不得不省略了很多东西。我们建议你花些时间仔细研究一下它的头文件和一些模块 (尤其是 ext/standard 目录下的一些文件以及 MySQL 模块,看一下这些众所周知的函数究竟是怎么实 现的),看一下别人是怎么使用这些 API 函数的,尤其是那些本章没有提到的那些函数。 由 buildconf 处理的配置文件 config.m4 包含了所有在配置过程中所执行的指令。这些指令诸如包含测 试包含所需的外部文件,像头文件、库文件等等。PHP 定义了一系列处理这类情况的宏,其中最常用的我 们已经在“表 3.18 config.m4 中的 M4 宏”列了出来。 表 3.18 config.m4 中的 M4 宏 宏 说明 AC_MSG_CHECKING(message) 在执行 configure 命令 时输出“checking