PHP扩展开发--编写一个helloWorld扩展

为何要用C扩展

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

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

下载PHP7.1.1扩展

1.下载地址: http://php.net/get/php-7.1.1.tar.bz2/from/a/mirror vim

2.下载后进行解压数组

建立扩展骨架

##本例用的是php7.1.1
cd ext
./ext_skel --extname=helloworld

修改config.m4

把下面几行注释打开,config.m4中 dnl 为注释的意思安全

##动态编译选项,经过.so的方式连接,去掉dnl注释:

PHP_ARG_WITH(helloworld, for helloworld support,
Make sure that the comment is aligned:
[  --with-helloworld             Include helloworld support])

##静态编译选项,经过enable来启用,去掉dnl注释:

 PHP_ARG_ENABLE(helloworld, whether to enable helloworld support,
 Make sure that the comment is aligned:
 [  --enable-helloworld           Enable helloworld support])

修改完成编译下php7

phpize
#这里用本身的php-config文件位置
./configure --with-php-config=./configure --with-php-config=/Applications/MAMP/bin/php/php7.1.1/bin/php-config 
make && make install
make test  #测试
#编辑php.ini,加上helloworld扩展
extension=helloworld.so

 

在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!\n");
        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);
}
相关文章
相关标签/搜索