扩展开发
什么是扩展开发
扩展是 PHP 的重要组成部分, 是 PHP 提供给开发者用于扩展 PHP 语言功能的主要方式. 开发者可以用 C/C++定义自己的功能, 然后嵌入到 PHP 中
扩展可以做到什么
- 介入 PHP 的编译,执行阶段: 可以介入 PHP 框架执行的那五个阶段, 比如 opcache,就是重新定义了编译函数
- 提供内部函数: 可以定义内部函数扩充 PHP 的函数功能, 比如 array, date 等操作
- 提供内部类
- 实现 RPC 客户端: 实现与外部服务器的交互, 比如 redis, mysql 等
- 提升执行性能: PHP 是解析型语言,在性能方面远不及 C 语言,可以将耗 CPU 的操作以 C 语言代替
PHP 中的扩展分为两类: PHP 扩展, Zend 扩展, 对内核而言, 这两个分别为: 模块(module), 扩展(extension)
扩展的实现原理
通过 zend_module_entry
这个结构表示, 这个结构定义了扩展的全部信息: 扩展名, 扩展版本, 扩展提供的函数列表, 以及 PHP 四个执行阶段 hook 函数等.
- zend_module_entry
- size
- zend_api
- zend_debug 是否开启 debug
- zts 是否开启线程安全
- *name 扩展名称, 不能重复
- _zend_function_entry *functions 扩展提供的内部函数列表
- module_startup_func 扩展初始化回调函数
- module_shutdown_func 扩展关闭时回调函数
- request_startup_func 请求开始前回调函数
- request_shutdown_func 请求结束前回调函数
- info_func php_info()函数时调用,用于展示一些配置、运行信息
- version 扩展版本
- type
- handle
- module_number 扩展的唯一编号
扩展的开发流程
编译工具
- ext_skel: ext 目录下, 用来生成扩展的基本骨架
- phpize: 操作复杂的
autoconf/automake/autoheader/autolocal
等命令,生成 configure 文件 - php-config: 主要是获取 PHP 的安装信息的
- PHP 安装路径
- PHP 版本
- PHP 源码的头文件目录
- LDFLAGS: 外部库路径
- 依赖的外部库: 告诉编译器要链接到哪些文件
- 扩展存放的目录
- 编译的 SAPI
- PHP 编译参数
编写扩展流程
- 通过 ext 目录下
ext_skel
脚本生成扩展的基本框架:./ext_skel --extname
- 修改
config.m4
配置: 设置编译配置参数, 设置扩展的源文件,依赖库/函数检查等等. - 编写扩展要实现的功能: 按照 PHP 扩展的格式以及 PHP 提供的 API 编写功能
- 生成 configure: 扩展写完以后执行 phpize 脚本生成 configure 及其它配置文件
- 编译&安装: ./configure, make, make install, 然后将扩展的.so 路径添加到 php.ini 中
扩展的运行流程
- dlopen()打开 so 库文件
- dlsym()获取动态库中
get_module()
函数的地址,get_module()是每个扩展都必须提供的一个接口,用于返回扩展zend_module_entry
结构的地址 - 调用
get_module()
, 获取扩展的zend_module_entry
结构 - zend api 版本检查, 比如 php7 扩展无法在 php5 上使用
- 注册扩展, 将扩展添加到
module_registry
中,这是一个全局 HashTable,用于全部扩展的zend_module_module
结构. - 如果扩展提供了内部函数则将这些函数注册到 EG(function_table)中