@@ -430,11 +430,133 @@ Zend能够确定一个块是否在使用,自动释放未使用的块和丢失
430430### 分析解决问题
431431===
432432
433- ...
433+ 实际上,当编译静态或动态模块时没有太多的故障排除可以做。唯一可能产生的问题是编译器会对未定义的或类似的东西发出警告。
434+ 在本例中,确保所有的头文件可用并且命令行中的路径正确。确保所有的东西放在正确的位置,获取一个干净的 PHP 源码树,
435+ 使用 ` ext ` 目录内的干净文件自动构建;这保证了一个安全的编译环境。如果失败,尝试手动编译。
434436
437+ PHP 可能同样编译你的模块中没有的函数。(如果在相同的源码中不修改它们不会发生这种情况。)如果从外部访问你模块的函数是拼写错误的,
438+ 它们会在符号表中以 "unlinked symbols" 保存。在被 PHP 动态加载和链接期间,类型错误不会被解析 - 在主二进制中没有相符的符号。
439+ 在你的模块文件里查找错误的定义或错误的外部引用。注意,这个问题特别是对动态加载的模块;它不会在动态模块中产生。
440+ 静态模块的错误会在编译时显示。
441+
442+ ### 根源讨论
443+ ===
444+
445+ 现在你已经有了一个安全的构建环境并且可以把模块引入到 PHP 文件中,是时候讨论这一切如何工作了。
446+
447+ #### 模块结构
448+
449+ 所有的 PHP 模块有共同的结构:
450+
451+ * 头文件包含(引入所有需要的宏,API定义,等。)
452+
453+ * C定义的导出函数(需要定义 Zend 函数块)
454+
455+ * Zend 函数块定义
456+
457+ * Zend 模块块定义
458+
459+ * ** get_module()** 实现
460+
461+ * 所有导出函数的实现
462+
463+ #### 头文件包含
464+
465+ 你模块真正需要包含的头文件是 ` php.h ` ,在PHP目录内。这个文件引入所有的宏和 API 来构建对代码可用的新模块。
466+
467+ * 提示* :为你的模块创建独立的包含模块特殊定义的头文件是个好的实践。这个头文件应该包含所有导出函数前面的定义并引入 ` php.h ` 。
468+ 如果你用 * ext_skel* 创建模块,你已经有了这样一个准备好的头文件。
469+
470+ #### 定义导出函数
471+
472+ 要定义导出函数(作为一个原生函数对 PHP 可用),Zend 提供一套宏。一个简单的定义如下:
473+
474+ ```
475+ ZEND_FUNCTION ( my_function );
476+ ```
477+
478+ * ZEND_FUNCTION* 定义了一个由 Zend 内部 API 编译的新的C函数。它的意思是函数类型是 * void* 并接收
479+ * INTERNAL_FUNCTION_PARAMETERS(another macro)* 作为参数。另外,它给函数名加 * zif* 前缀。
480+ 上面定义的展开版本如下:
481+
482+ ```
483+ void zif_my_function ( INTERNAL_FUNCTION_PARAMETERS );
484+ ```
485+
486+ 展开 * INTERNAL_FUNCTION_PARAMETERS* 结果如下:
487+
488+ ```
489+ void zif_my_function( int ht
490+ , zval * return_value
491+ , zval * this_ptr
492+ , int return_value_used
493+ , zend_executor_globals * executor_globals
494+ );
495+ ```
496+
497+ 由于解释器和执行器核心已经从主要的 PHP 包中分离出来,第二种定义宏和函数设置的API已逐步演化:Zend API。
498+ 所以 Zend API 现在处理很少的先前属于PHP的责任,大量的 PHP 函数已经缩减为调用 Zend API 的宏别名。
499+ 推荐的实践是任何使用 Zend API 的地方,旧的API只作兼容性维护。例如,zval 和 pval 是相同的。zval 是 Zend 的定义;
500+ pval 是 PHP 的定义(实际上,pval 现在是 zval 的别名)。由于 * INTERNAL_FUNCTION_PARAMETERS* 宏现在是一个 Zend 宏,
501+ 上面的定义包含 zval。当写代码时,你应该总是使用 zval 确保是新的 Zend API。
502+
503+ 这个定义的参数列表非常重要;你应该记住这些参数:
504+ Zend's Parameters to Functions Called from PHP
505+
506+ | 参数 | 描述
507+ |--- |---
508+ | ht | 传递给 Zend 函数的参数个数。你应该避免直接接触,而用 ZEND_NUM_ARGS() 获取值。
509+ | return_value | 这个变量用来从你的函数返回值给 PHP。访问这个值的最好方式是用预定义宏。具体描述见下面。
510+ | this_ptr | 使用这个变量,你可以访问你函数中含有的对象,如果在对象中使用。使用函数 ** getThis()** 来获取这个指针。
511+ | return_value_used | 这个标记标明这个函数最终的返回值是否实际被脚本使用。0表明没有使用;1标明调用者使用了。<br />这个标记的评估可以用来验证函数的正确使用 以及 在返回值需要很高代价的例子中的速度优化(例如,看 array.c 如何使用它)。
512+ | executor_globals | 这个变量指向 Zend 引擎的全局设置。你在创建新变量时会发现很有用,(更多例子在后面)。<br />执行器全局变量同样可以用宏 * TSRMLS_FETCH()* 引入到你的函数中。
513+
514+ #### Zend 函数块定义
515+
516+ 现在你已经定义了导出函数,你同样需要引入 Zend 中。使用 Zend_function_entry 来引入函数列表。
517+ 这个数组连续包含所有的函数使它在外部可用,带有希望出现在PHP中的函数名和在C源码中定义的名。在内部,zend_function_entry 定义如下:
518+
519+ Example #4 Internal declaration of zend_function_entry.
520+
521+ ```
522+ typedef struct _zend_function_entry {
523+ char *fname;
524+ void (*handler)(INTERNAL_FUNCTION_PARAMETERS);
525+ unsigned char *func_arg_types;
526+ } zend_function_entry;
527+ ```
528+
529+ | 名字 | 描述
530+ |--- |---
531+ | fname | 表示PHP中可见的函数名(如,fopen,mysql_connect,或在我们的例子中,first_module)。
532+ | handler | 指向C函数负责处理函数调用。如,见前面讨论的标准宏 * INTERNAL_FUNCTION_PARAMETERS*
533+ | func_arg_types | 允许你标记指定的参数,这样它们被强制以引用方式传递。你通常应该设为 NULL。
534+
535+ 在上面的例子中,定义看起来像这样:
536+
537+ ```
538+ zend_function_entry firstmod_functions[] =
539+ {
540+ ZEND_FE(first_module, NULL)
541+ {NULL, NULL, NULL}
542+ };
543+ ```
544+
545+ 你可以看到数组中最后一个记录是 {NULL, NULL, NULL}。这个标记设置用来让 Zend 知道何时到达导出函数的结尾。
546+
547+ ```
548+ Note:
549+ 你不能使用预定义宏给结尾的标记,因为它会尝试指向一个 “NULL” 名字的函数!
550+ ```
551+
552+
553+ 后面雷同,参考前面 1~ 7 章节.
554+
555+ ---
435556
436557### 调用用户使用的函数 [ Calling User Functions ]
437558===
559+
438560你可以在自己的模块中调用用户函数,当实现回调时非常有用;例如,数组回调,检索,或简单的事件驱动程序。
439561
440562用户函数可以用 ` call_user_function_ex() ` 来调用。它需要一个你想访问得函数表的哈希值,一个指向对象的指针(如果想使用方法),
@@ -521,6 +643,7 @@ Return value: 'hello'
521643
522644### 初始化文件支持
523645===
646+
524647PHP4以重新设计的文件支持为特色。现在直接在代码中指定默认的初始化方式已成为可能,在运行时读取和改变这些值,
525648并且为更改通知创建消息句柄。
526649
@@ -605,6 +728,7 @@ ZEND_MSHUTDOWN_FUNCTION(mymodule)
605728
606729### 从这儿去哪儿
607730===
731+
608732你已经学了很多关于PHP的。你知道如何创建动态加载的模块并静态链接的扩展。你已经学了PHP和Zend变量的内部存储并能创建和访问这些变量。
609733你知道相当一套做许多常规任务的工具函数如打印信息字符,自动绑定变量到符号表,等等。
610734
@@ -614,6 +738,23 @@ ZEND_MSHUTDOWN_FUNCTION(mymodule)
614738
615739### 参考:一些配置宏
616740===
617- ** config.m4**
618741
742+ #### config.m4
619743
744+ 文件 ` config.m4 ` 由 ` buildconf ` 处理,并且必须包含配置期间所有要执行的命令。例如,它们可以是包含测试的外部文件,如头文件,库,等。
745+ PHP 定义了一套宏用于这个处理,最有用的描述如下。
746+
747+ | 宏 | 描述
748+ |--- |---
749+ | * AC_MSG_CHECKING(message)* | 配置期间打印一个 "checking <message >" 文本。
750+ | * AC_MSG_RESULT(value)* | 把结果给 * AC_MSG_CHECKING* ; 应该指定为 yes 或 no。
751+ | * AC_MSG_ERROR(message)* | 配置期间打印消息和错误消息并终止脚本。
752+ | * AC_DEFINE(name, value, description)* | 添加 ` #define ` 到 * php_config.h* ,以value为值,并含有描述(这对模块的条件式编译很有用)。
753+ | * AC_ADD_INCLUDE(path)* | 添加一个含路径的编译器;例如,如果模块需要添加头文件的检索路径时使用。
754+ | * AC_ADD_LIBRARY_WITH_PATH(libraryname, librarypath)* | 指定链接的一个其它库
755+ | * AC_ARG_WITH(modulename, description, unconditionaltest, conditionaltest)* | 相当强大的宏,添加模块描述到 configure --help 输出。<br />PHP检测选项 --with-<modulename > 是否传给了配置脚本。如果是,它运行非条件式的脚本(如 --with-myext=yes),<br />例子中选项值保存在 $withval 中。否则,它执行条件检测。
756+ | * PHP_EXTENSION(modulename, [ shared] )* | 这个调用PHP配置你的扩展的宏是必须的。你可以应用第二个参数标示是否想要编译为共享模块。<br />这将在编译时为你的代码产生一个定义 * COMPILE_DL_ <modulename >*
757+
758+ ---
759+
760+ 后面雷同,参考前面第3章节
0 commit comments