欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  后端开发

php扩展如何嵌入到php框架中

程序员文章站 2022-04-17 11:29:00
...
编写一个简单的扩展示例

使用php内置工具生成自定义扩展的框架。该工具在ext文件夹下面

./ext_skel --extname=wully

Ext_skel的主要参数(这里面只列举了最常用的两个)

--extname=module module is the name of your extension【必须有的】

生成模块的名称,会自动在ext内建立extname文件夹,最常用的

--proto=file file contains prototypes of functions to create【可选】

函数原型定义文件

官方说明地址:

http://www.php.net/manual/en/internals2.buildsys.skeleton.php

修正ext/wully/config.m4

修正后,运行:

./buildconf --force

./configure --enable-wully

Make & make install 及可以安装成功

可以通过运行 ext/wully/wully.php来校验是否安装成功

扩展的内部实现


依旧以生成的wully模块为例,这个模块的提供的外部函数在

const zend_function_entry wully_functions[]这里面陈列(wully.c),我们可以看到示例中定义的函数为

PHP_FE(confirm_wully_compiled, NULL)

这个模块的外部函数和模块在php请求各个阶段的调用逻辑是通过

wully_module_entry(zend_module_entry)结构传给php框架的

php扩展函数的实现逻辑

每一个扩展函数都是通过PHP_FUNCTION来实现的,例如我们的示例,通过PHP_FUNCTION(confirm_wully_compiled) 来实现的

内部如何获取php函数的参数

生成的源码函数为:

zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len)

这个是一个参数,且参数类型为字符串的情况

调用的原型为:

zend_parse_parameters(int num_args TSRMLS_DC, char *type_spec, …);

有两个参数我们要特别注意下:

第一个参数为该函数获取的参数个数

第三个参数为php函数传过来的参数类型,下表是一个对应关系图

后面的参数则是参数的值,及参数的大小,第二个参数对应于线程安全,这里面先不关心

参数类型对应表

类型指定符

对应的C类型

描述

l

long

符号整数

d

double

浮点数

s

char *, int

二进制字符串,长度

b

zend_bool

逻辑型(1或0)

r

zval *

资源(文件指针,数据库连接等)

a

zval *

联合数组

o

zval *

任何类型的对象

O

zval *

指定类型的对象。需要提供目标对象的类类型

z

zval *

无任何操作的zval

再看一个三个参数,一个为字符串,两个为整数

zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sll", &arg, &arg_len,&n,&m)

PHP_FUNCTION展开模式:

#define PHP_FUNCTION ZEND_FUNCTION

#define ZEND_FUNCTION(name) ZEND_NAMED_FUNCTION(ZEND_FN(name))

#define ZEND_FN(name) zif_##name

#define ZEND_NAMED_FUNCTION(name) void name(INTERNAL_FUNCTION_PARAMETERS)

#define INTERNAL_FUNCTION_PARAMETERS int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_value_used TSRMLS_DC

提供外部函数列表的展开模式,即PHP_FE

#define PHP_FE ZEND_FE

#define ZEND_FE(name, arg_info) ZEND_FENTRY(name, ZEND_FN(name), arg_info, 0)

#define ZEND_FENTRY(zend_name, name, arg_info, flags) { #zend_name, name, arg_info, (zend_uint) (sizeof(arg_info)/sizeof(struct _zend_arg_info)-1), flags },

按照php处理请求的各个阶段我们分为 mint rint script rshutdown mshutdown,我们自定义的外部扩展对请求的各个阶段也可以进行相应的干预。


各个阶段的干预接口为:


MINIT阶段:模块初始化阶段

对应PHP_MINIT(wully)的实现

在sapi的start阶段,调用zend_startup_module

ZEND_API int zend_startup_module(zend_module_entry *module)执行两个动作注册模块,启动模块

注册模块

zend_register_internal_module(module TSRMLS_CC)

把module放入 module_registry 中,其中 module_registry 为一个全局的hash tab

启动模块

zend_startup_module_ex(module TSRMLS_CC) == SUCCESS

检测依赖是否就绪,然后运行该module的 PHP_MINIT函数

MINIT宏展开模式:

#define PHP_MINIT ZEND_MODULE_STARTUP_N

#define ZEND_MINIT ZEND_MODULE_STARTUP_N

#define ZEND_MODULE_STARTUP_N(module) zm_startup_##module

RINIT阶段:请求初始化

对应PHP_RINIT(wully)的实现

int php_request_startup(TSRMLS_D)

void zend_activate_modules(TSRMLS_D)

int module_registry_request_startup(zend_module_entry *module TSRMLS_DC)

module->request_startup_func(module->type, module->module_number TSRMLS_CC)

RINIT宏展开模式

#define PHP_RINIT ZEND_MODULE_ACTIVATE_N

#define ZEND_RINIT ZEND_MODULE_ACTIVATE_N

#define ZEND_MODULE_ACTIVATE_N(module) zm_activate_##module

script阶段

我们的PHP_FUNCTION执行在script阶段,他们作为php语言编译和解释的一部分,纳入到opcode的执行中

PHP_RSHUTDOWN阶段:请求关闭

对应PHP_RSHUTDOWN(wully))的实现

void php_request_shutdown(void *dummy)

void zend_deactivate_modules(TSRMLS_D)

int module_registry_cleanup(zend_module_entry *module TSRMLS_DC)

module->request_shutdown_func(module->type, module->module_number TSRMLS_CC)

PHP_RSHUTDOWN 宏展开模式

#define PHP_RSHUTDOWN ZEND_MODULE_DEACTIVATE_N

#define ZEND_MODULE_DEACTIVATE_N(module) zm_deactivate_##module

PHP_MSHUTDOWN阶段:模块关闭

对应PHP_MSHUTDOWN(wully))的实现

在zend_startup中注册模块销毁时的析构函数

int zend_startup(zend_utility_functions *utility_functions, char **extensions TSRMLS_DC)

zend_hash_init_ex(&module_registry, 50, NULL, ZEND_MODULE_DTOR, 1, 0);

#define ZEND_MODULE_DTOR (void (*)(void *)) module_destructor

void module_destructor(zend_module_entry *module)

module->module_shutdown_func(module->type, module->module_number TSRMLS_CC);

PHP_MSHUTDOWN 宏展开模式

#define PHP_MSHUTDOWN ZEND_MODULE_SHUTDOWN_N

#define ZEND_MODULE_SHUTDOWN_N(module) zm_shutdown_##module

PHP_MINFO跟前面的宏意义有所不同,主要用于在phpinfo中显示模块的信息

#define PHP_MINFO ZEND_MODULE_INFO_N

#define ZEND_MINFO ZEND_MODULE_INFO_N