运行环境:
PHP7.0以上版本和以下版本创建流程和使用的函数可能会有些差异
第一步,先生成一个扩展骨架
cd php-7.1.10
cd ext
./ext_skel --extname=classextension
vim classextension/config.m4
去掉前面的dnl
dnl PHP_ARG_ENABLE(.....
dnl [ --enable.....)
:wq
退出并保存
第二步, 修改classextension.c
, 比如我们要增加一个类名为Person
, 并拥有一个静态成员函数叫say
, 这个函数的作用就是打印给定的字符串到终端.
PHP_METHOD(Person, say)
{
zend_string *message;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STR(message);
ZEND_PARSE_PARAMTERS_END();
php_printf("%s", (char *)ZSTR_VAL(message));
RETURN_TRUE;
}
定义一个方法时, 我们使用PHP_METHOD
宏, 这个宏有两个参数,类名和方法名。定义好了方法,PHP引擎如何知道你定义的方法需要几个参数呢?这个时候又要用到另外一个宏 ZEND_BEGIN_ARG_INFO_EX
对需要参数进行描述.
ZEND_BEGIN_ARG_INFO_EX(arginfo_say_message, 0, 0, 1)
ZEND_ARG_INFO(0, message)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX
有四个参数
ZEND_ARG_INFO
有两个参数
上面我们提到创建的方法为类的静态方法, 那PHP引擎如何知道这个方法为静态方法?定义一个函数实体集, 并使用PHP_ME
宏.
const zend_function_entry classextension_functions[] = {
PHP_ME(Person, say, arginfo_say_message, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_FE_END;
};
PHP_ME
有四个参数
最终把定义好的方法注册到PHP引擎中
PHP_MINIT_FUNCTION(classextension)
{
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "Person", classextension_functions);
zend_register_internal_class(&ce);
return SUCCESS;
}
我们的函数最终会被解析成下面这个样子:
void Person_say(zend_execute_data *execute_data, zval *return_value)
{
zend_string *message;
//这段太长了, 就不贴了
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STR(message);
ZEND_PARSE_PARAMTERS_END();
php_printf("%s", (char *)ZSTR_VAL(message));
do {
(*return_value).u1.type_info = IS_TRUE;
return;
} while (0);
}
编译这个扩展, 并加入到php.ini
phpize
./configure && make && sudo make install
查找php.ini
的位置
php -i | grep ini
# 一般ini文件在/usr/local/lib下
vim /usr/local/lib/php.ini
extension_dir = "扩展目录绝对路径"
extension=classextension.so
再运行php -m | grep classextension
, 看看是否成功.
运行php -r "Person::say('hello');"
看看结果.