PHP 扩展开发小结

1.变量操作
    设置变量 ZVAL_*系列函数;
        例:
        zval t;
        ZVAL_STRING(t,"10",2);
    获取变量 Z_* 系列函数
    获取变量指针 Z_*_P 系列函数
    获取变量指针的指针 Z_*_PP 系列函数
        例:
        Z_STRVAL(t);
        Z_STRLEN(t);
    变量类型转换 convert_to_* 系列函数
        例:
        convert_to_long_ex(t);
    获取变量类型 Z_TYPE Z_TYPE_P Z_TYPE_PP 可以同 IS_* 系列常量对比
        例:
        if(Z_TYPE_P(filehandle)!=IS_LONG)
            php_printf("this is long type!");
    申请变量的内存  一般 ALLOC_ZVAL(zv) ,MAKE_STD_ZVAL(zv)宏,用完释放 FREE_ZVAL(zv)等宏
    释放变量内存 zval_dtor(zval)  zval_ptr_dtor(&zval); FREE_ZVAL(zval);
        注意:FREE_ZVAL 只释放zval结构体内存,而zval_dtor会释放zval变量及value指针内存
    打印变量 php_printf("hi function!"); 返回输出流,可以使用 php_write() 继续写
    字符串变量生成函数 spprintf(char **pbuf, size_t max_len, const char *format, ...); 用完释放efree();
    申请内存并复制字符串的副本 estrdup(&a) estrndup(&a,10);
    变量内存申请:emalloc(size) efree(ptr) 不要用malloc 除非你能明确释放掉
    
2.全局变量辅助宏:
    EG(v);//全局变量 executor_globals 如$_GLOBALS[EG(symbol_table),地址:EG(active_symbol_table)
    PG(v);//核心变量 php_core_globals 如:$_GET $_POST .. PG(http_globals)[TRACK_VARS_*],INI信息
    SG(v);//SAPI变量 请求数据 sapi_globals_struct 如:HTTP原始请求变量 sapi_request_info
    CG(v);//编译变量 compiler_globals 可以得到函数表,类表
    EX(v);//当前执行数据 zend_execute_data 可以获取到当前执行的函数,类,OPCODE等
    OG(v);//输出变量 output_globals 
    
3.函数,分5类 ZEND_*_FUNCTION 以下为C定义内置函数
    函数参数说明 FOR C:
        int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_value_used 
        ht 参数个数,但不能直接使用,该用 ZEND_NUM_ARGS()获取
        return_value 函数返回zval
        return_value_ptr 返回值的指针,但想控制返回值的内容,不是直接返回返回值时候用到,如参数引用实现.
        this_ptr 如果当前方法是一个对象的方法,此值指向该方法指向的对象,不能直接使用,使用 getThis() 函数
        return_value_used 返回值有没有被使用
        例:
        int argc = ZEND_NUM_ARGS();
        char *str=NULL;
        int strlen;
        //注意:字符串参数为指针的指针 长度为整形的指针
        if (zend_parse_parameters(argc TSRMLS_CC, "s|s",&str,&strlen) ==FAILURE) {
          return;
        }
    关于返回
        修改 return_value_ptr 指针指向要用ALLOC_ZVAL_*宏申请内存,
        参考:http://www.walu.cc/phpbook/6.1.md
        返回的宏 RETURN_*系列函数,资源用 ZEND_REGISTER_RESOURCE 
        RETURN_ZVAL(); 返回zval结构
            如果是申请的内存,RETURN_ZVAL(zv, copy, dtor) copy 0 dtor 0
            如果是堆栈内存 RETURN_ZVAL(zv, copy, dtor) copy 1 dtor 0

4.数组与HASH表
    1. zvalue_value 是个union 数组时为 hashtable
    2. hashtable 表有很对对应的处理函数:zend_hash_*系列函数
    3. 数组上的HASHTABLE一般不直接操作,通过add_*系列函数处理
    4. hashtable 内存申请 ALLOC_HASHTABLE 等宏处理,用完释放FREE_HASHTABLE
    5. 数组初始化也不要用直接处理hashtable,使用 array_init 处理

5.资源变量
    1. 需要使用资源变量须先得到一个资源列表
    参数:1.请求资源,每次请求会清空此请求的资源列表
         2.永久资源,服务启动后永久保存
         3.显示资源名
         4.内部管理参数,忽略
    le_myfile = zend_register_list_destructors_ex(myfile_dtor,NULL,"standard-c-file", module_number);
    static void myfile_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC){
         FILE *fp = (FILE *) rsrc->ptr;//转换指定类型,方便以后操作
         fclose(fp);
    }
    2. 把资源注册进资源列表,并设置return_value
    int r=ZEND_REGISTER_RESOURCE(return_value, fp, le_myfile);
    3. 查询资源
    filehandle 为资源zval 
    ZEND_FETCH_RESOURCE(fp, FILE *, &filehandle, -1, "standard-c-file",le_myfile);
    if (fp == NULL){
      RETURN_FALSE;
    }
    4.删除资源
    filehandle 为资源zval 
    if (zend_list_delete(Z_RESVAL_P(filehandle)) == FAILURE) {
        RETURN_FALSE;
    }
     
5.全局函数
    zend_function_entry test_functions[] =
    {
        //参数 : 函数名 
        ZEND_FE(myecho, NULL)
        {NULL, NULL, NULL}
    };
    注册到模块中
    zend_module_entry php_test_module_entry = {
    #if ZEND_MODULE_API_NO >= 20010901
        STANDARD_MODULE_HEADER,
    #endif
        "my test ext",//模块名
        test_functions,//函数列表
        NULL,
        NULL,
        NULL,
        NULL,
        PHP_MINFO(php_test),//模块介绍
    #if ZEND_MODULE_API_NO >= 20010901
        "1.6.0", //版本
    #endif
        STANDARD_MODULE_PROPERTIES
    };
    //函数实现,参考 3.函数部分
    PHP_FUNCTION(myecho){}
    用户函数调用:
    参数:
        function_table 函数表,全局从&CG(function_table)得到
        对象,如果该函数是对象的方法,没有传NULL
        函数名
        返回值存储 zval指针,
        参数数量
        参数数组
    call_user_function(HashTable *function_table, zval **object_pp, zval *function_name, zval *retval_ptr, zend_uint param_count, zval *params[] TSRMLS_DC);
     
6.类的实现,结构:zend_class_entry 分两种 ZEND_INTERNAL_CLASS 和 ZEND_USER_CLASS
    //访问权限控制:ZEND_ACC_*系列宏
    //类方法定义
    //参数:类名 方法名 
    ZEND_METHOD( myclass , public_method )
    {
        php_printf("hi function!");
    }
    //注册到函数列表
    static zend_function_entry myclass_method[]={
        //参数:类名 方法名 静态方法加 ZEND_ACC_STATIC
        ZEND_ME(myclass,    public_method,    NULL,    ZEND_ACC_PUBLIC)
        {NULL,NULL,NULL}
    };
    zend_class_entry ce;
    zend_class_entry *myclass_ce;
    //参数:初始结构 类名 方法列表
    INIT_CLASS_ENTRY(ce,"myclass",myclass_method);
    //此方法会根据ce拷贝生成一个zend_class_entry并挂载到类列表中
    zend_register_internal_class(&ce TSRMLS_CC);
    //添加类的属性
    //参数:类指针 属性名 属性名长度 属性访问权限 : zend_declare_property_* 系列函数
    zend_declare_property_null(myclass_ce, "public_var", strlen("public_var"), ZEND_ACC_PUBLIC TSRMLS_CC);
    
    //定义类常量:
    //参数:类指针 属性名 属性名长度 属性访问权限 : zend_declare_class_constant* 系列函数
    zend_declare_class_constant_null(myclass_ce, "aaa", 3 TSRMLS_DC);
    
    读取类静态属性
        ZEND_API zval *zend_read_static_property(
            zend_class_entry *scope, 
            char *name, 
            int name_length, 
            //属性不存在是否抛出 notice
            zend_bool silent TSRMLS_DC
        );
    更新类静态属性
        ZEND_API int zend_update_static_property(
            zend_class_entry *scope, 
            char *name, 
            int name_length, 
            zval *value TSRMLS_DC
        );
    其他封装的快捷函数 zend_update_static_property_*
    

7.接口 结构也是: zend_class_entry
    static zend_function_entry i_myinterface_method[]={
        //注意这里的null指的是arg_info,具体可以参考:参数 arg_info 的定义
        ZEND_ABSTRACT_ME(i_myinterface, hello, NULL) 
        {NULL,NULL,NULL}
    };
    //定义及初始化
    zend_class_entry ce;
    INIT_CLASS_ENTRY(ce, "i_myinterface", i_myinterface_method);
    i_myinterface_ce = zend_register_internal_interface(&ce TSRMLS_CC);

8.继承及接口实现
    1.实现接口:
        写完类,接口后添加:
        参数: 类指针 ,实现接口数量,接口指针...
        zend_class_implements(class_ce TSRMLS_CC,1,myinterface_ce);
    2.实现继承:
        注册类时候使用: zend_register_internal_class_ex
        参数: 类指针 父类指针 父类名
        myclass_ce = zend_register_internal_class_ex(&ce,parent_class_ce,"parent_class" TSRMLS_CC);

8.对象 zend_object_value
    结构:
    typedef struct _zend_object_value {
        //unsigned int类型,EG(objects_store).object_buckets的索引
        zend_object_handle handle;
        zend_object_handlers *handlers;
    } zend_object_value;
    创建对象:
    zval *obj;
    MAKE_STD_ZVAL(obj);
    object_init_ex(obj, zend_class_entry 类名 );
    //object_init(obj) 空对象
    读取属性:
    ZEND_API zval *zend_read_property(
        zend_class_entry *scope, 
        zval *object, 
        char *name, 
        int name_length, 
        //属性不存在是否抛出 notice
        zend_bool silent TSRMLS_DC
    );
    更新属性:
    ZEND_API int zend_update_static_property(
        zend_class_entry *scope, 
        char *name, 
        int name_length, 
        zval *value TSRMLS_DC
    );
    其他封装的快捷函数 zend_update_property_*
    调用方法:
        ZEND_API zval* zend_call_method(zval **object_pp, zend_class_entry *obj_ce, zend_function **fn_proxy, const char *function_name, int function_name_len, zval **retval_ptr_ptr, int param_count, zval* arg1, zval* arg2 TSRMLS_DC);
        zend_call_method_with_0_params(obj, obj_ce, fn_proxy, function_name, retval)
        zend_call_method_with_1_params(&this_zval,myclass_ce,NULL,"hello",NULL);

9.常用结构及宏解释:
    PHP_FN(name) 函数名生成
    PHP_MN(name) 方法名生成
    ZEND_NAMED_FUNCTION(name) 生成指定名的函数 一般用
    PHP_FUNCTION(name) 函数声明
    ZEND_METHOD(classname, name) 类方法声明
    
    zend_function_entry    数组用于声明模块或类的成员函数情况
    生成zend_function_entry的元素配套宏:
        //注册全局的函数
        //参数:函数名 参数
        PHP_FE(name, arg_info) 
        //注册类的函数
        //参数:类名 方法名 参数 访问权限控制
        PHP_ME(classname, name, arg_info, flags) 
        //注册类的抽象函数,类和接口都用这个
        //参数:类名 方法名 参数
        PHP_ABSTRACT_ME(classname, name, arg_info) 
        
10.参数 arg_info 的定义
    一般情况下不需要定义参数,除非你希望PHP般你检查参数正确性,比如接口方法
    生成arg_info的宏,以arg_say_hello为例:
    //参数:zend_arg_info 名,参数至少前N个
    ZEND_BEGIN_ARG_INFO(arg_say_hello, 0)
    //参数:是否设置为引用,参数名
    //ZEND_ARG_* 系列函数还可以声明对象等
    ZEND_ARG_INFO(0, name)
    ZEND_END_ARG_INFO()
    //其他介绍
    //name    参数名称
    //name_len    参数名称字符串长度
    //class_name    当参数类型为类时,指定类名称
    //class_name_len    类名称字符串长度
    //array_type_hint    标识参数类型是否为数组
    //allow_null    是否允许设置为空
    //pass_by_ref    是否设置为引用,即使用&操作符
    //return_reference    标识函数将重写return_value_ptr,后面介绍函数返回值时再做介绍
    //required_num_args    设置函数被调用时,传递参数至少为前N个,当设置为-1时,必须传递所有参数

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。