深入php内核五(开始创建扩展)
我们先来创建一个非常简单的扩展,这个扩展除了一个将其整形参数作为返回值的函数外几乎什么都没有。下面(“例3-2 一个简单的扩展”)就是这个样例的代码:
例3.2 一个简单的扩展
/* include standard header */
#include "php.h"
/* declaration of functions to be exported */
ZEND_FUNCTION(first_module);
/* compiled function list so Zend knows what's in this module */
zend_function_entry firstmod_functions[] =
{
ZEND_FE(first_module, NULL)
{NULL, NULL, NULL}
};
/* compiled module information */
zend_module_entry firstmod_module_entry =
{
STANDARD_MODULE_HEADER,
"First Module",
firstmod_functions,
NULL,
NULL,
NULL,
NULL,
NULL,
NO_VERSION_YET,
STANDARD_MODULE_PROPERTIES
};
/* implement standard "stub" routine to introduce ourselves to Zend */
#if COMPILE_DL_FIRST_MODULE
ZEND_GET_MODULE(firstmod)
#endif
/* implement function that is meant to be made available to PHP */
ZEND_FUNCTION(first_module)
{
long parameter;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", ¶meter) == FAILURE) {
return;
}
RETURN_LONG(parameter);
}
这段代码已经包含了一个完整的 PHP 模块。稍后我们会详细解释这段代码,现在让我们先讨论一下构建过程。(在我们讨论 API函数前,这可以让心急的人先实验一下。)
模块的编译
模块的编译基本上有两种方法:
1、在 Ext 目录内使用“make” 机制,这种机制也可以编译出动态可加载模块。
2、手动编译源代码。
第一种方法明显受到人们的偏爱。自 PHP 4.0 以来,这也被标准化成了一个的复杂的构建过程。这种复杂性也导致了难于被理解这个缺点。在本章最后我们会更详细的讨论这些内容,但现在还是让我们使用默认的 make 文件吧。
第二种方法很适合那些(因为某种原因而)没有完整 PHP 源码树的或者是很喜欢敲键盘的人。虽然这些情况是比较罕见,但为了内容的完整性我们也会介绍一下这种方法。
使用 make 进行编译
为了能够使用这种标准机制流程来编译这些代码,让我们把它所有的子目录都复制到 PHP 源码树的 Ext 目录下。然后运行 buildconf 命令,这将会创建一个新的包含了与我们的扩展相对应的选项的 configure 脚本。默认情况下,样例中的所有代码都是未激活的,因此你不用担心会破坏你的构建程序。在 buildconf 执行完毕后,再使用 configure –help 命令就会显示出下面的附加模块:
–enable-array_experiments BOOK: Enables array experiments
–enable-call_userland BOOK: Enables userland module
–enable-cross_conversion BOOK: Enables cross-conversion module
–enable-first_module BOOK: Enables first module
–enable-infoprint BOOK: Enables infoprint module
–enable-reference_test BOOK: Enables reference test module
–enable-resource_test BOOK: Enables resource test module
–enable-variable_creation BOOK: Enables variable-creation module
前面样例(“例3-2 一个简单的扩展”)中的模块(first_module)可以使用–enable-first_module 或 –enable-first_module=yes 来激活。
手动编译
手动编译需要运行以下命令:
动作 | 命令 |
编译 | cc -fpic -DCOMPILE_DL=1 -I/usr/local/include -I. -I.. -I../Zend -c -o <your_object_file> <your_c_file> |
连接 | cc -shared -L/usr/local/lib -rdynamic -o <your_module_file> <your_object_file(s)> |
编译命令只是简单的让编译器产生一些中间代码(不要忽略了-fpic 参数),然后又定义了COMPILE_DL 常量来通知代码这是要编译为一个动态可加载的模块(通常用来测试,我们稍后会讨论它)。这些选项后面是一些编译这些源代码所必须包含的库文件目录。
注意:本例中所有 include 的路径都是都是Ext 目录的相对路径。如果您是在其他目录编译的这些源文件,那么还要相应的修改路径名。编译所需要的目录有 PHP 目录,Zend 目录和模块所在的目录(如果有必要的话)。
连接命令也是一个非常简单的把模块连接成一个动态模块的命令。
你可以在编译指令中加入优化选项,尽管这些已经在样例中忽略了(不过你还是可以从前面讨论的make 模版文件中发现一些)。
注意,手动将模块静态编译和连接到 PHP 二进制代码的指令很长很长,因此我们在这里不作讨论。(手动输入那些指令是很低效的。)