• PHP扩展开发--01.编写一个helloWorld扩展


    为什么要用C扩展

    C是静态编译的,执行效率比PHP代码高很多。同样的运算代码,使用C来开发,性能会比PHP要提升数百倍。

    另外C扩展是在进程启动时加载的,PHP代码只能操作Request生命周期的数据,C扩展可操作的范围更广。

    创建扩展骨架

    ##本例用的php版本的是5.3.3
    cd php-5.3.3/ext/
    ./ext_skel --extname=myfun --proto=myfun.def
    ##执行成功后会生成myfun的编译文件
    ls myfun/
    config.m4  config.w32  CREDITS  .cvsignore  EXPERIMENTAL  myfun.c  myfun.php  php_myfun.h  tests
    

    修改config.m4

    config.m4中 dnl 为注释的意思

    ##动态编译选项,通过.so的方式链接,去掉dnl注释
    PHP_ARG_WITH(myfun, for myfun support,
    [  --with-myfun             Include myfun support])
    ##静态编译选项,通过enable来启用,去掉dnl注释
    PHP_ARG_ENABLE(myfun, whether to enable myfun support,
    [  --enable-myfun           Enable myfun support])
    

    修改完成编译下

    phpize
    ./configure --enable-myfun
    make
    make install
    

    在myfun有个php的测试脚本,执行测试下

    php -d enable_dl=On myfile.php
    

    输出结果:

    Functions available in the test extension:
    confirm_myfun_compiled
    
    Congratulations! You have successfully modified ext/myfun/config.m4. Module myfun is now compiled into PHP.
    

    其实confirm_myfun_compiled是构建工具帮我们生成的测试函数

    创建helloWorld函数

    现在我们来创建属于自己的函数 helloWorld(),功能就是输出 Hello World!

    vim myfun/php_myfun.h
    ##在PHP_FUNCTION(confirm_myfun_compiled); 下追加一行
    PHP_FUNCTION(helloWorld);
    

    实现helloworld实体

     vim myfun/myfun.c
    
    ##zend_function_entry myfun_functions 补充要实现的函数
    
    const zend_function_entry myfun_functions[] = {
            PHP_FE(confirm_myfun_compiled,     NULL)           /* For testing, remove later. */
            PHP_FE(helloWorld,     NULL)  /*这是补充的一行,末尾没有逗号*/
            {NULL, NULL, NULL}      /* Must be the last line in myfun_functions[] */
    };
    
    ##在末尾实现helloworld的内容
    PHP_FUNCTION(helloWorld)
    {
            php_printf("Hello World!
    ");
            RETURN_TRUE;
    }
    

    重新编译

    ./configure && make && make install
    

    测试

    php -d enable_dl=On -r "dl('myfun.so');helloWorld();"
    Hello World!
    php -d enable_dl=On -r "dl('myfun.so');print confirm_myfun_compiled('helloWorld');"
    Congratulations! You have successfully modified ext/myfun/config.m4. Module helloWorld is now compiled into PHP.
    

    头文件分析

    #ifndef PHP_MYFUN_H
    #define PHP_MYFUN_H
    
    extern zend_module_entry myfun_module_entry;
    #define phpext_myfun_ptr &myfun_module_entry
    
    #ifdef PHP_WIN32
    #       define PHP_MYFUN_API __declspec(dllexport)
    #elif defined(__GNUC__) && __GNUC__ >= 4
    #       define PHP_MYFUN_API __attribute__ ((visibility("default")))
    #else
    #       define PHP_MYFUN_API
    #endif
    
    #ifdef ZTS
    #include "TSRM.h"
    #endif
    
    PHP_MINIT_FUNCTION(myfun); /*当PHP被装载时,模块启动函数即被引擎调用。这使得引擎做一些例如资源类型,注册INI变量等的一次初始化。*/
    PHP_MSHUTDOWN_FUNCTION(myfun);  /*当PHP完全关闭时,模块关闭函数即被引擎调用。通常用于注销INI条目*/
    PHP_RINIT_FUNCTION(myfun); /*在每次PHP请求开始,请求前启动函数被调用。通常用于管理请求前逻辑。*/
    PHP_RSHUTDOWN_FUNCTION(myfun); /*在每次PHP请求结束后,请求前关闭函数被调用。经常应用在清理请求前启动函数的逻辑。*/
    PHP_MINFO_FUNCTION(myfun); /*调用phpinfo()时模块信息函数被呼叫,从而打印出模块信息。*/
    
    PHP_FUNCTION(confirm_myfun_compiled);   /* For testing, remove later. */
    PHP_FUNCTION(helloWorld);
    
    #ifdef ZTS
    #define MYFUN_G(v) TSRMG(myfun_globals_id, zend_myfun_globals *, v)
    #else
    #define MYFUN_G(v) (myfun_globals.v)
    #endif
    
    #endif  /* PHP_MYFUN_H */
    

    confirm_myfun_compiled分析

    PHP_FUNCTION(confirm_myfun_compiled)  //使用了宏PHP_FUNCTION(),该宏可以生成一个适合于Zend引擎的函数原型
    {
            char *arg = NULL;
            int arg_len, len;
            char *strg;
            //获得函数传递的参数
            //第一个参数是传递给函数的参数个数。通常的做法是传给它ZEND_NUM_ARGS()。这是一个表示传递给函数参数总个数的宏。
            //第二个参数是为了线程安全,总是传递TSRMLS_CC宏。
            //第三个参数是一个字符串,指定了函数期望的参数类型,后面紧跟着需要随参数值更新的变量列表。因为PHP采用松散的变量定义和动态的类型判断,这样做就使得把不同类型的参数转化为期望的类型成为可能。例如,如果用户传递一个整数变量,可函数需要一个浮点数,那么zend_parse_parameters()就会自动地把整数转换为相应的浮点数。如果实际值无法转换成期望类型(比如整形到数组形),会触发一个警告。
            /*
             类型指示符
             l   long        符号整数
             d   double      浮点数
             s   char *, int 二进制字符串,长度
             b   zend_bool   逻辑型(1或0)
             r   zval *      资源(文件指针,数据库连接等)
             a   zval *      联合数组
             o   zval *      任何类型的对象
             O   zval *      指定类型的对象。需要提供目标对象的类类型
             z   zval *      无任何操作的zval
            */
            //第四个参数为传递的参数数据的引用
            //第五个参数为传递的参数个数
            if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) {  //获得函数传递的参数
                    return;
            }
    
            len = spprintf(&strg, 0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.",     "myfun", arg);
    
            /*
              通过设置RETURN_type()的方式,将返回控制到PHP。下表解释了大多数存在的宏。
              RETVAL_LONG(l)  整数
              RETVAL_BOOL(b)  布尔数(1或0)
              RETVAL_NULL()   NULL
              RETVAL_DOUBLE(d)    浮点数
              RETVAL_STRING(s, dup)   字符串。如果dup为1,引擎会调用estrdup()重复s,使用拷贝。如果dup为0,就使用s
              RETVAL_STRINGL(s, l, dup)   长度为l的字符串值。与上一个宏一样,但因为s的长度被指定,所以速度更快。
              RETVAL_TRUE     返回布尔值true。注意到这个宏没有括号。
              RETVAL_FALSE    返回布尔值false。注意到这个宏没有括号。
              RETVAL_RESOURCE(r)  资源句柄。
            */
            RETURN_STRINGL(strg, len, 0);
    }
    




  • 相关阅读:
    Appium安装教程
    方法(method)和函数(function)有什么区别?
    FTP两种工作模式:主动模式(Active FTP)和被动模式介绍
    python socket编程介绍
    面向对象基础篇
    python fishc.homework2
    python遇到的问题汇总
    我对 python 面向对象的理解
    深入理解JVM(五)JVM优化策略
    深入理解JVM(四)JVM性能监控与故障处理工具
  • 原文地址:https://www.cnblogs.com/linzhenjie/p/5485512.html
Copyright © 2020-2023  润新知