扩展开发教程·函数

开发环境:PHP-8.2
 
 
 
下载PHP源码并解压,注意选择和当前环境相同的版本
[root@localhost ~]# wget https://www.php.net/distributions/php-*.*.*.tar.gz
 
 
 
创建扩展骨架,执行完命令后会在PHP源码的ext目录下生成该扩展的目录
[root@localhost ~]# /program/php/bin/php /program/php/src/ext/ext_skel.php --ext demo_profile
Copying config scripts... done
Copying sources... done
Copying tests... done
 
Success. The extension is now ready to be compiled. To do so, use the
following steps:
 
cd /program/php/src/ext/demo_profile
phpize
./configure
make
 
Don't forget to run tests once the compilation is done:
make test
 
Thank you for using PHP!
[root@localhost ~]#
 
 
 
在扩展目录下有一个demo_profile.stub.php文件,里面自带了test1()和test2()两个函数原型,开发者仿照原型定义自己的函数即可
[root@localhost ~]# vim /program/php/src/ext/demo_profile/demo_profile.stub.php
<?php
 
/**
 * @generate-class-entries
 * @undocumentable
 */
 
function test1(): void {}
 
function test2(string $str = ""): string {}
 
// 增加intro()函数
function intro(string $name = '匿名', string $gender = '保密', int $birth = 1970): string {}
[root@localhost ~]#
说明:由于是函数原型,所以只需要声明形参和返回值即可,无需实现函数功能(函数功能是在“扩展名.c”文件里使用C语言实现)。
 
 
 
使用工具解析加入了自定义函数的demo_profile.stub.php文件,并根据解析内容更新demo_profile_arginfo.h文件
[root@localhost ~]# cd /program/php/src/ext/demo_profile
[root@localhost demo_profile]# /program/php/bin/php ../../build/gen_stub.php demo_profile.stub.php
[root@localhost demo_profile]# cat demo_profile_arginfo.h
…………(此处省略内容若干)…………
Saved demo_profile_arginfo.h
[root@localhost demo_profile]# cat demo_profile_arginfo.h
/* This is a generated file, edit the .stub.php file instead.
 * Stub hash: **************************************** */
 
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_test1, 0, 0, IS_VOID, 0)
ZEND_END_ARG_INFO()
 
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_test2, 0, 0, IS_STRING, 0)
        ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, str, IS_STRING, 0, "\"\"")
ZEND_END_ARG_INFO()
 
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_intro, 0, 0, IS_STRING, 0)
        ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, name, IS_STRING, 0, "\'匿名\'")
        ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, gender, IS_STRING, 0, "\'保密\'")
        ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, birth, IS_LONG, 0, "1970")
ZEND_END_ARG_INFO()
 
 
ZEND_FUNCTION(test1);
ZEND_FUNCTION(test2);
ZEND_FUNCTION(intro);
 
 
static const zend_function_entry ext_functions[] = {
        ZEND_FE(test1, arginfo_test1)
        ZEND_FE(test2, arginfo_test2)
        ZEND_FE(intro, arginfo_intro)
        ZEND_FE_END
};
[root@localhost demo_profile]#
说明①:开发者可以直接手动修改demo_profile_arginfo.h的代码,但是并不建议这样做,因为demo_profile_arginfo.h可以根据demo_profile.stub.php生成,而维护*.php文件比维护*.h文件更简单,尤其是实现复杂的类,由于有很多属性和方法,如果手动修改*.h文件那么工作量会很庞大且繁琐。
说明②:解析工具需要从GitHub下载(只需下载一次),国内可能会下载失败。
 
 
 
在demo_profile.c文件里实现扩展功能
[root@localhost ~]# vim /program/php/src/ext/demo_profile/demo_profile.c
/* {{{ string intro( [ string $name = '匿名', string $gender = '保密', int $birth = 1970 ] ) */
PHP_FUNCTION(intro)
{
    char *name = "匿名";
    size_t name_len = sizeof("匿名") - 1;
 
    char *gender = "保密";
    size_t gender_len = sizeof("保密") - 1;
 
    zend_long birth = 1970;
 
    zend_string *retval;
 
    /* (0, 3)表示intro()有0个必填参数,共有3个参数(不分选填和必填),也就是3个参数均为选填 */
    ZEND_PARSE_PARAMETERS_START(0, 3)
        Z_PARAM_OPTIONAL /* Z_PARAM_OPTIONAL是必填参数和选填参数的分界线,上面是必填,下面是选填 */
        Z_PARAM_STRING(name, name_len)     /* 获取name参数   */
        Z_PARAM_STRING(gender, gender_len) /* 获取gender参数 */
        Z_PARAM_LONG(birth)                /* 获取birth参数  */
    ZEND_PARSE_PARAMETERS_END();
 
    retval = strpprintf(0, "俺叫%s(%s),出生于%ld年。", name, gender, birth);
 
    RETURN_STR(retval);
}
/* }}}*/
[root@localhost ~]#
说明:PHP_FUNCTION(test1)和PHP_FUNCTION(test2)就是demo_profile.stub.php文件里的test1()和test2()两个函数原型的具体实现,开发者也在这里实现自己的intro()函数功能即可。
 
 
 
编译扩展就没什么需要特别说明的了,和编译官方扩展是一样的
[root@localhost ~]# cd /program/php/src/ext/demo_profile
[root@localhost demo_profile]# /program/php/bin/phpize
[root@localhost demo_profile]# ./configure --with-php-config=/program/php/bin/php-config
[root@localhost demo_profile]# make
[root@localhost demo_profile]# make install
 
 
 
启用扩展并重启PHP-FPM即可
[root@localhost ~]# vim /program/php/php.ini
extension=demo_profile
[root@localhost ~]# service php-fpm restart
 
 
 
重新编译命令
[root@localhost ~]# cd /program/php/src/ext/demo_profile && \
/program/php/bin/php ../../build/gen_stub.php demo_profile.stub.php && \
/program/php/bin/phpize && \
./configure --with-php-config=/program/php/bin/php-config && \
make clean && make && make install && \
service php-fpm restart
 
 
 
在PHP脚本中调用扩展的函数

<?php
declare(strict_types=1);
ini_set('display_errors', 'On');
error_reporting(-1);

test1();

echo 'test2() => 0个参数:' . test2() . PHP_EOL;
echo 'test2() => 1个参数:' . test2('程序猿') . PHP_EOL;

echo 'intro() => 0个参数:' . intro() . PHP_EOL;
echo 'intro() => 1个参数:' . intro('张三') . PHP_EOL;
echo 'intro() => 2个参数:' . intro('张三', '男') . PHP_EOL;
echo 'intro() => 3个参数:' . intro('张三', '男', 2003) . PHP_EOL;

// The extension demo_profile is loaded and working!
// test2() => 0个参数:Hello World
// test2() => 1个参数:Hello 程序猿
// intro() => 0个参数:俺叫匿名(保密),出生于1970年。
// intro() => 1个参数:俺叫张三(保密),出生于1970年。
// intro() => 2个参数:俺叫张三(男),出生于1970年。
// intro() => 3个参数:俺叫张三(男),出生于2003年。

Copyright © 2024 码农人生. All Rights Reserved