php扩展开发入门

来源:互联网 发布:java飞机大战扇形子弹 编辑:程序博客网 时间:2024/05/22 05:18

我们要开发的扩展的php原型是:

<?php// 调用一个可变参函数,输出函数名和参数,返回调用后的结果function calltask(callable $func[, mixed $arg1[, ...]]);// 原型可变参写法function calltask(... $args) {    $func = array_shift($args);    if (!is_callable($func)) {        printf("the function is not callable:%s\n", $func);        return false;    }    // 输出    printf("you call func:%s\n", $func);    foreach ($args as $i=>$arg) {        printf("arg[%d] type=%d len=%d val=%s \n", $i, typeof($arg), strlen($arg), strval($arg));    }    return $func(... $args);}

我的开发环境是:

系统: CentOS 7
PHP: 7.0+
gcc :4.8.4
PHP已经提供了工具用来创建扩展,并初始化代码:ext_skel

$ cd php-src/ext$ ./ext_skel --extname=hello

工具会在当前目录生成 hello 文件夹。

修改配置文件
cd到hello,工具已经初始化了目录,打开配置文件 config.m4:

dnl If your extension references something external, use with:dnl PHP_ARG_WITH(hello, for hello support,dnl Make sure that the comment is aligned:dnl [  --with-hello             Include hello support])dnl Otherwise use enable:dnl PHP_ARG_ENABLE(hello, whether to enable hello support,dnl Make sure that the comment is aligned:dnl [  --enable-hello           Enable hello support])

dnl 是注释符,表示当前行是注释。这段话是说如果此扩展依赖其他扩展,去掉PHP_ARG_WITH段的注释符;否则去掉PHP_ARG_ENABLE段的注释符。显然我们不依赖其他扩展或lib库,所以去掉PHP_ARG_ENABLE段的注释符:

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

书写代码
工具生成的hello.c,写上我们的实现:

/* proto function calltask(callable $func[, mixed $arg1[, ...]]);*/PHP_FUNCTION(calltask){    int i, status, argc = ZEND_NUM_ARGS();    zval *args = NULL;    zval retval;    // use FAST_ZPP get any count of args, args use original args pointer, no need to free here#ifndef FAST_ZPP    if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {        RETURN_FALSE;    }   #else    ZEND_PARSE_PARAMETERS_START(1, -1)         Z_PARAM_VARIADIC('+', args, argc)    ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);#endif    if (argc < 1) {        WRONG_PARAM_COUNT;    }       // 第一个参数为函数名 取出来    zval *thefunc = &(args[0]);    php_printf("you will call: %s argc=%d is_callable=%d\n", Z_STRVAL(*thefunc), argc, zend_is_callable(thefunc, IS_CALLABLE_CHECK_NO_ACCESS, NULL));    if (!zend_is_callable(thefunc, IS_CALLABLE_CHECK_NO_ACCESS, NULL)) {        php_printf("the function is not callable:%s\n", Z_STRVAL(*thefunc));        RETURN_FALSE;    }       // 从第二个参数开始,把参数打印出来    for (i=1; i<argc; i++) {        convert_to_string_ex(&args[i]);        php_printf("arg[%d] type=%d len=%d val=%s \n", i, Z_TYPE(args[i]), Z_STRLEN(args[i]), Z_STRVAL(args[i]));    }       // 使用zend_API.h中的call_user_function_ex调用    status = call_user_function_ex(EG(function_table), NULL, thefunc, &retval, argc-1, (argc>1?args+1:NULL), 0, NULL);    // 判断返回值    if (status == SUCCESS && !Z_ISUNDEF(retval)) {        php_printf("the function success:%d\n", status);        //zval_ptr_dtor(return_value);        //ZVAL_COPY_VALUE(return_value, &retval);    } else {        php_printf("the function failed:%d\n", status);        //zval_ptr_dtor(return_value);        //ZVAL_NULL(return_value);    }       php_printf("the call over: %s argc=%d status=%d\n", Z_STRVAL(*thefunc), argc);    //efree(args);// Z_PARAM_VARIADIC 的args指针来自于复制函数原参数指针,不需要free    RETURN_ZVAL(&retval, 1, 1);//RETURN_TRUE;// 返回该返回值的类型}

添加到编译列表里:

const zend_function_entry hello_functions[] = {    PHP_FE(hello, NULL)  /*添加这行*/    PHP_FE(confirm_hello_compiled,  NULL)       /* For testing, remove later. */    PHP_FE_END  /* Must be the last line in hello_functions[] */};

编译与安装

$ phpize$ ./configure --with-php-config=/usr/local/php7/bin/php-config$ make && make install

修改php.ini,开启扩展,若找不到可以用phpinfo()查看使用哪个配置文件.
make install会输出你的php扩展的路径:

Installing shared extensions:     /usr/local/php/lib/php/extensions/no-debug-non-zts-20151012/

其实不用关心这个路径。相信来学习扩展开发的同学都知道哪里配置php.ini,如何重启对应的apache或者fpm,这里不多说。

extension=hello.so

写个脚本测试,此脚本在ext_skel会自动生成, hello.php:

<?php$br = (php_sapi_name() == "cli")? "":"<br>";if(!extension_loaded('hello')) {    dl('./module/hello.' . PHP_SHLIB_SUFFIX);}$module = 'hello';/* 测试打印扩展中的函数列表$functions = get_extension_funcs($module);echo "Functions available in the test extension:$br\n";foreach($functions as $func) {    echo $func."$br\n";}echo "$br\n";$function = 'confirm_' . $module . '_compiled';if (extension_loaded($module)) {    $str = $function($module);} else {    $str = "Module $module is not compiled into PHP";}echo "called in script: $str\n";*///$ret = calltask($function, 100, 2.2);$func2 = function(... $args) {    $args[0] = "make a str:".$args[0];    return sprintf(... $args);};$func1 = 'printf';//$ret = calltask($func1, 'FORMAT_FROM_PARAM:%s:%d\n', date('Y-m-d H:i:s'), __LINE__);$ret = calltask($func2, 'FORMAT_FROM_PARAM:%s:%d\n', date('Y-m-d H:i:s'), __LINE__);echo "the ret in php=";var_dump($ret);

输出:

you will call: ??argc=4 is_callable=1arg[1] type=6 len=25 val=FORMAT_FROM_PARAM:%s:%d\n arg[2] type=6 len=19 val=2017-08-01 19:09:14 arg[3] type=6 len=2 val=28 the function success:0the call over: ??argc=4 status=8the ret in php=string(53) "make a str:FORMAT_FROM_PARAM:2017-08-01 19:09:14:28\n"

运行成功。
祝小伙伴们开发顺利。

原创粉丝点击