·天新网首页·加入收藏·设为首页·网站导航
数码笔记本手机摄像机相机MP3MP4GPS
硬件台式机网络服务器主板CPU硬盘显卡
办公投影打印传真
家电电视影院空调
游戏网游单机动漫
汽车新车购车试驾
下载驱动源码
学院开发设计
考试公务员高考考研
业界互联网通信探索
您现在的位置:天新网 > 软件开发 > Web开发 > PHP开发
PHP内核介绍及扩展开发指南—Extensions 的编写(上)
http://www.21tx.com 2012年09月08日 百度搜索研发部官方博客 zhangdongjin

1 2 下一页

Extensions 的编写

理解了这些运行机制以后,本章着手介绍Extensions 的编写,但凡写程序的人都知道hello world,那好,就从hello world开始。

1.1Hello World

这是摘自《PHP手册》的示例程序:

/* 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);  
}

这段代码实现了一个简单的extension,首先它包含了“php.h”,这是所有extensions都需要包含的头文件,它定义、声明了我们可以访问的所有Zend数据结构、常量和API等。下面对剩余的步骤进行解释。

1.1.1  声明导出函数

ZEND_FUNCTION(first_module);

ZEND_FUNCTION宏用于声明一个可在PHP代码中调用的函数,其参数即成为PHP函数名,因此,这一句声明了一个名为first_module的PHP函数,将其展开如下:

void zif_first_module (INTERNAL_FUNCTION_PARAMETERS);  
     
// 最终展开得:  
void zif_first_module (  
int ht,  
zval * return_value,  
zval **return_value_ptr,  
zval * this_ptr,  
int return_value_used  
);

可见,ZEND_FUNCTION就是简单的声明了一个名为zif_ first_module的C函数,zif可能是”Zend Internal Function”的缩写。函数的原型满足Zend引擎对PHP函数的调用约定,关于其参数将在后面章节进行解释。

1.1.2  声明导出函数块

声明C函数后,Zend并不知道如何调用,我们需要使用如下的语句来完成C函数到PHP函数的映射:

zend_function_entry firstmod_functions[] =  
{  
ZEND_FE(first_module, NULL)  
{NULL, NULL, NULL}  
};

这创建了一个zend_function_entry数组,zend_function_entry存储了关于如何调用该PHP函数的信息,通过它Zend引擎就能够理解和调用我们的函数。

其定义如下:

typedef struct _zend_function_entry {  
    char *fname;  
    void (*handler)(INTERNAL_FUNCTION_PARAMETERS);  
    struct _zend_arg_info *arg_info;  
    zend_uint num_args;  
    zend_uint flags;  
} zend_function_entry;

fname是PHP函数名,是PHP代码能够通过它来调用我们的函数;handler是指向我们在前面声明的C函数的函数指针。这两个参数已经足以完成从C函数到PHP函数的映射。剩余的参数用于告诉Zend该PHP函数对于函数参数的要求,arg_info是个数组,它的每一项都描述了对应下标的参数,num_args是参数的个数,具体将在后面的章节介绍。

我们可以手动填充一个zend_function_entry,但更好的办法是使用Zend提供的宏ZEND_FE,因为Zend并不保证这个结构以后不会变。ZEND_FE使用第一个参数作为PHP函数名,并且在添加了zif前缀后作为C函数名;第二个参数用于填充arg_info,通常使用NULL。上面的代码将得到这样一个zend_function_entry结构:{” first_module,”, zif_first_module, NULL, 0, 0}。当然,这并不是说PHP函数名必须和C函数名有什么关系,也可以通过宏ZEND_NAMED_FE来手动指定PHP函数名,不过这并不是个好主意。

我们必须为希望导出的每一个C函数都创建一个zend_function_entry结构,并将其放到一个数组中以备后用,数组最后一项的成员必须全部为NULL,这用于标记数组的结束。

1.1.3  填写模块信息

下一步需要将我们的模块介绍给Zend,主要包括我们的模块名和导出的函数,这通过填充一个zend_module_entry结构来完成。

zend_module_entry firstmod_module_entry =
{
   STANDARD_MODULE_HEADER,
   "First Module",
   firstmod_functions,
   NULL,
   NULL,
   NULL,
   NULL,
   NULL,
   NO_VERSION_YET,
   STANDARD_MODULE_PROPERTIES
};

STANDARD_MODULE_HEADER和STANDARD_MODULE_
PROPERTIES宏填充了该结构的首尾部分,具体填充了什么并不是我们需要关心的,并且为了兼容后续版本也最好不要手工修改。

第二、三项是模块名称和导出函数,名称可以任意填写,导出函数就是我们在前面准备好的zend_function_entry数组。

接下来的五个参数是函数指针,其用法在后面介绍,这里只用NULL填充。

下面的参数是一个C字符串,用于表示模块版本,如果没有则使用NO_VERSION_YET,其实就是NULL。

填写完毕后,需要把这个结构传给Zend引擎,这通过下面的语句完成:

#if COMPILE_DL_FIRST_MODULE  
ZEND_GET_MODULE(firstmod)  
#endif

宏开关用于判断是否是动态链接的,动态链接时才会执行下面的语句,本文仅介绍动态链接的模块,并不关心静态链接时如何与Zend交流信息,因此,可以认为条件总为真。
ZEND_GET_MODULE(firstmod)最后展开得到名为get_module的一个函数:

zend_module_entry *get_module(void)  
{  
return &firstmod_module_entry;  
}

这个函数就是简单的返回我们填充的zend_module_entry结构,这里需要注意的是结构的名称必须是xxx_module_entry,xxx是传递给ZEND_GET_MODULE的参数。当Zend加载我们的模块时,它首先会解析并调用名为get_module的函数,这样就可以得到我们的zend_module_entry,于是,PHP代码就可以调用模块导出的函数了。

1.1.4 实现导出函数

代码最后一部分实现了我们导出的函数:

ZEND_FUNCTION(first_module)  
{  
long parameter;  
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l",  
?meter) == FAILURE)  
return;  
RETURN_LONG(parameter);  
}

这里依然要用ZEND_FUNCTION来声明函数原型,函数体通过Zend API和宏,访问了函数参数并返回一个long值——这些都将在后面的章节进行详细介绍。

1.2使用参数

函数的一个重要部分就是访问参数,但由于extension的特殊性,我们无法像通常的函数那样来访问参数。

上一篇: php打印warning日志引发的core追查
下一篇: 大话PHP之性能

1 2 下一页

关于我们 | 联系我们 | 加入我们 | 广告服务 | 投诉意见 | 网站导航
Copyright © 2000-2011 21tx.com, All Rights Reserved.
晨新科技 版权所有 Created by TXSite.net