本文目录导读:

我来详细介绍 PHP 扩展包(PHP Extension)的开发流程,包括从环境搭建到发布的完整过程。
开发环境准备
1 安装必要工具
# Ubuntu/Debian sudo apt-get install php-dev php-pear autoconf build-essential # CentOS/RHEL sudo yum install php-devel autoconf make gcc gcc-c++ # macOS brew install autoconf
2 获取 PHP 源码(可选)
# 下载对应版本的 PHP 源码 wget https://www.php.net/distributions/php-8.2.0.tar.gz tar -xzf php-8.2.0.tar.gz
扩展骨架生成
1 使用 ext_skel 工具
# 进入 PHP 源码的 ext 目录 cd php-8.2.0/ext # 生成扩展骨架 ./ext_skel --extname=myextension # 或者使用 pecl 工具 pecl gen-ext myextension
2 生成的目录结构
myextension/
├── config.m4 # 构建配置
├── config.w32 # Windows 配置
├── php_myextension.h # 头文件
├── myextension.c # 扩展主文件
├── myextension.php # 测试文件
├── tests/ # 测试目录
│ └── 001.phpt # 测试用例
└── package.xml # PECL 包配置
编写扩展代码
1 修改 config.m4
# 去掉 PHP_ARG_ENABLE 前的注释
PHP_ARG_ENABLE(myextension, whether to enable myextension support,
[ --enable-myextension Enable myextension support])
if test "$PHP_MYEXTENSION" != "no"; then
PHP_NEW_EXTENSION(myextension, myextension.c, $ext_shared)
fi
2 编写主头文件 php_myextension.h
#ifndef PHP_MYEXTENSION_H
#define PHP_MYEXTENSION_H
extern zend_module_entry myextension_module_entry;
#define phpext_myextension_ptr &myextension_module_entry
#define PHP_MYEXTENSION_VERSION "0.1.0"
#ifdef PHP_WIN32
# define PHP_MYEXTENSION_API __declspec(dllexport)
#elif defined(__GNUC__) && __GNUC__ >= 4
# define PHP_MYEXTENSION_API __attribute__ ((visibility("default")))
#else
# define PHP_MYEXTENSION_API
#endif
#ifdef ZTS
#include "TSRM.h"
#endif
#endif /* PHP_MYEXTENSION_H */
3 编写主实现文件 myextension.c
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_myextension.h"
/* 声明函数 */
PHP_FUNCTION(myextension_hello);
PHP_FUNCTION(myextension_add);
/* 参数信息 */
ZEND_BEGIN_ARG_INFO_EX(arginfo_myextension_hello, 0, 0, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_myextension_add, 0, 0, 2)
ZEND_ARG_INFO(0, a)
ZEND_ARG_INFO(0, b)
ZEND_END_ARG_INFO()
/* 函数表 */
static const zend_function_entry myextension_functions[] = {
PHP_FE(myextension_hello, arginfo_myextension_hello)
PHP_FE(myextension_add, arginfo_myextension_add)
PHP_FE_END
};
/* 模块入口 */
zend_module_entry myextension_module_entry = {
STANDARD_MODULE_HEADER,
"myextension",
myextension_functions,
NULL, /* MINIT */
NULL, /* MSHUTDOWN */
NULL, /* RINIT */
NULL, /* RSHUTDOWN */
NULL, /* MINFO */
PHP_MYEXTENSION_VERSION,
STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_MYEXTENSION
ZEND_GET_MODULE(myextension)
#endif
/* 实现 hello 函数 */
PHP_FUNCTION(myextension_hello)
{
RETURN_STRING("Hello from myextension!");
}
/* 实现 add 函数 */
PHP_FUNCTION(myextension_add)
{
zend_long a, b;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_LONG(a)
Z_PARAM_LONG(b)
ZEND_PARSE_PARAMETERS_END();
RETURN_LONG(a + b);
}
构建和编译
1 构建配置
# 在扩展目录执行 phpize ./configure --enable-myextension make
2 安装
make install
3 启用扩展
# php.ini 添加 extension=myextension.so
测试扩展
1 创建测试文件
// test.php <?php echo myextension_hello() . "\n"; echo myextension_add(5, 3) . "\n"; // 输出 8
2 编写 PHPT 测试
--TEST--
Test myextension_hello function
--SKIPIF--
<?php if (!extension_loaded('myextension')) die('skip extension not loaded'); ?>
--FILE--
<?php
echo myextension_hello();
?>
--EXPECT--
Hello from myextension!
运行测试:
make test
高级功能开发
1 定义类和对象
/* 定义类方法 */
PHP_METHOD(MyClass, __construct);
PHP_METHOD(MyClass, getName);
/* 类入口 */
zend_class_entry *myclass_ce;
/* 注册类 */
PHP_MINIT_FUNCTION(myextension)
{
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "MyClass", myclass_methods);
myclass_ce = zend_register_internal_class(&ce);
return SUCCESS;
}
2 处理数组和资源
PHP_FUNCTION(myextension_process_array)
{
zval *arr;
HashTable *ht;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ARRAY(arr)
ZEND_PARSE_PARAMETERS_END();
ht = Z_ARRVAL_P(arr);
/* 遍历数组 */
zend_hash_internal_pointer_reset(ht);
while (zend_hash_has_more_elements(ht) == SUCCESS) {
zend_string *key;
zval *value;
zend_hash_move_forward(ht);
}
}
调试和优化
1 启用调试模式
# 编译时启用调试 CFLAGS="-g -O0" ./configure --enable-debug --enable-myextension make
2 使用 Valgrind
valgrind --tool=memcheck php test.php
3 内存管理建议
/* 正确使用内存 */
zend_string *str = zend_string_init("Hello", 5, 0);
php_printf("%s", ZSTR_VAL(str));
zend_string_release(str);
/* 安全处理资源 */
zend_resource *res = zend_register_resource(handle, resource_type);
发布流程
1 生成 PECL 包
# 更新 package.xml pecl package
2 提交到 PECL
# 创建账号并提交 pecl upload myextension-0.1.0.tgz
3 文档编写
// README.md # MyExtension ## 安装 ```bash pecl install myextension
使用
echo myextension_hello();
## 九、最佳实践
### 9.1 代码规范
- 遵循 PSR 标准编码风格
- 注释完整,便于维护
- 使用 PHP 官方命名约定
### 9.2 性能优化
```c
/* 使用 hashtable 加速 */
static HashTable myextension_global_data;
ZEND_INI_MH(update_myextension_setting)
{
/* 配置更新处理 */
}
/* 使用缓存 */
ZEND_BEGIN_MODULE_GLOBALS(myextension)
zend_long cache_size;
bool enabled;
ZEND_END_MODULE_GLOBALS(myextension)
3 兼容性考虑
- 支持 PHP 7.0+ 和 PHP 8.0+
- 提供 Windows 构建配置
- 使用条件编译处理版本差异
#if PHP_MAJOR_VERSION >= 8
/* PHP 8+ 的 API */
#else
/* PHP 7 的 API */
#endif
4 安全注意事项
- 使用
Z_PARAM_*宏进行参数验证 - 处理大整数溢出
- 防止内存泄漏
- 避免使用
eval等危险功能
CI/CD 集成
# GitHub Actions 示例
name: PHP Extension CI
on: [push, pull_request]
jobs:
build:
strategy:
matrix:
php-version: ['7.4', '8.0', '8.1', '8.2']
steps:
- uses: actions/checkout@v2
- uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
tools: phpize
- name: Build
run: |
phpize
./configure --enable-myextension
make
- name: Test
run: make test
PHP 扩展开发是一个系统性的工程,从环境搭建、代码编写、调试测试到发布维护,需要掌握 C 语言、PHP 内部机制和构建工具等多方面知识,建议从简单的扩展开始,逐步增加复杂度,并充分利用官方文档和社区资源。