PHP内核介绍及扩展开发指南——Extensions 的编写:启动和终止函数、调用PHP函数

2012-11-28 12:23 阅读 692 次 评论关闭

一、基础知识

PHP内核介绍及扩展开发指南——基础知识:PHP变量的存储

PHP内核介绍及扩展开发指南——基础知识:HashTable结构

二、Extensions 的编写

PHP内核介绍及扩展开发指南——Extensions 的编写:Hello World

PHP内核介绍及扩展开发指南——Extensions 的编写:使用参数

PHP内核介绍及扩展开发指南——Extensions 的编写:返回值

 

2.4   启动和终止函数

Zend允许模块在加载和卸载时收到通知,以进行初始化和清除工作,我们要做的就是把相应函数传递给Zend,它会在合适的时机自动调用。2.1.3节里留下的五个NULL就是用于这个目的,它们都是函数指针,最后一个用于配合phpinfo()来显示模块信息,在此忽略,只看其他四个。

Zend提供了如下四个宏,分别用于声明对应的函数:

意义

ZEND_MODULE_STARTUP_D(module)

在加载模块时调用

ZEND_MODULE_SHUTDOWN_D(module)

在卸载模块时调用

ZEND_MODULE_ACTIVATE_D(module)

一个页面开始运行时调用

ZEND_MODULE_DEACTIVATE_D(module)

一个页面运行完毕时调用

 

这些宏的用法和ZEND_FUNCTION宏一样(参见2.1.1),展开后就是声明了特定原型的函数,其参数module可以是任意的,但最好使用模块名称。这些函数的参数中,对我们有用的是int module_number,它是模块号,全局唯一,后面会提到其用处。

在声明和实现相应函数时,都应该使用这些宏。最后,需要把这些函数填写到zend_module_entry里(参见2.1.3),可按顺序使用如下的宏,这些宏生成相应的函数名称:

ZEND_MODULE_STARTUP_N(module)

ZEND_MODULE_SHUTDOWN_N(module)

ZEND_MODULE_ACTIVATE_N(module)

ZEND_MODULE_DEACTIVATE_N(module)

 

 

 

 

2.5   调用PHP函数

有时我们需要在模块中调用用户指定的函数,比如我们实现了sort这样的函数,并且允许用户指定比较函数。这可以使用如下的Zend函数:

int call_user_function_ex(

HashTable *function_table,

zval **object_pp,

zval *function_name,

zval **retval_ptr_ptr,

zend_uint param_count,

zval **params[],

int no_separation,

HashTable *symbol_table

TSRMLS_DC)

第一个参数是HashTable,在1.2.3节提到Zend使用HashTable来存储PHP函数,function_table用于指定从哪个HashTable中获取函数。通常应该用CG(function_table),展开就是compiler_globals.function_table,compiler_globals是一个用来存储编译器数据的全局数据结构(与其对应的还有个EG宏,即executor_globals,它用来存储执行器数据)。compiler_globals.function_table里面存储了所有我们可以在PHP页面里面调用的函数,包括Zend内建函数、PHP标准库函数、模块导出的函数以及用户使用PHP代码定义的函数。

object_pp是一个对象,当指定该值时,Zend会从对象的函数表中获取函数,这里不予讨论,总是设为NULL。

function_name必须是string型的zval,存储我们希望调用的函数的名称。为什么使用zval而不是直接用char*,是因为Zend考虑到大部分情况下,我们都是从用户那获得参数,然后再调用call_user_function_ex的,这样就可以不作处理直接把用户参数传给该函数。当然,我们也可以手动创建一个string型zval传给它。

retval_ptr_ptr用于获取函数的返回值,Zend执行完指定的函数后,它就将返回值的指针填充到这里。

param_count和params用于指定函数的参数,params是个zval **这点可能让人感到奇怪,但考虑到该函数的常见用法(见下面的示例)以及2.2.2节关于函数参数的介绍,就一点也不奇怪了。

no_separation用于指定是否在必要时执行zval分离(参见1.1.3),这在写入非引用zval时发生。应该总是将其设为0,表示执行zval分离,否则可能破坏数据。

symbol_table用于指定目标函数的active_symbol_table(参见1.2.3),通常应该使用NULL,这样Zend会为目标函数生成一个空的符号表。

说了这么多,该动动手了,下面的程序片段简单实现了PHP API call_user_func的功能:

ZEND_FUNCTION(call)

{

    int num_args = ZEND_NUM_ARGS();

    if(num_args < 1)

        WRONG_PARAM_COUNT;

    zval ***args = (zval***)emalloc(sizeof(zval**)*num_args);

zval *ret_zval;

// 获取传入的参数

if(zend_get_parameters_array_ex(num_args, args TSRMLS_CC)

== FAILURE)

    {

        efree(args);

        return;

}

// 第一个参数作为函数名,后面的作为函数参数

if(call_user_function_ex(CG(function_table), NULL, **args,

     &ret_zval, num_args - 1, args + 1, 0, NULL TSRMLS_CC)

== FAILURE)

    {

        efree(args);

        zend_error(E_ERROR, "Function call failed");

}

// 将函数返回值反馈给用户

    *return_value = *ret_zval;

    efree(args);

}

下载专辑 

PHP内核介绍及扩展开发指南.doc

 

编写 PHP Extension

zhangdongjin@baidu.com

版权声明:本文著作权归原作者所有,欢迎分享本文,谢谢支持!
转载请注明:PHP内核介绍及扩展开发指南——Extensions 的编写:启动和终止函数、调用PHP函数 | 猎微网

评论已关闭!