根本原因是缺失完整开发工具链,而非未安装phpize;必须安装对应PHP版本的php-dev或php-devel包,并补全autoconf、automake、libtool等依赖,同时确保php-config路径正确且版本匹配。

phpize 编译失败:根本不是“没装 phpize”
绝大多数人卡在第一步,以为装了 PHP 就能编译扩展——其实 phpize 只是构建脚本生成器,它背后依赖的是完整的开发链。报错如 Cannot find php-config 或 aclocal: command not found,说明环境缺关键组件。
- 必须安装对应 PHP 版本的开发包:
php-dev(Debian/Ubuntu)或php-devel(RHEL/CentOS/Fedora),仅装php运行时包不行 - 确认
php-config存在且版本匹配:which php-config+php-config --version,若用 asdf/phpenv 管理多版本,先phpenv local 8.7 - GNU Build System 缺失时补全:
apt install autoconf automake libtool(Linux)或brew install autoconf automake libtool(macOS)
zend_parse_parameters 参数解析崩得毫无征兆
函数一调就 segfault 或 Warning “Wrong parameter count or type”,90% 是 zend_parse_parameters() 用错了。它不报编译错误,但内存读写越界会直接炸。
- 整数参数必须用
zend_long *接收(PHP 8+ 统一类型),不能用int *——64 位系统上会读错 4 字节以外的栈内存 - 字符串参数必须同时传
char **和size_t *,例如zend_parse_parameters(zend_num_args(), "s", &str, &str_len);漏掉&str_len后续memcpy就越界 - 可选参数用
|分隔,且所有变量必须显式初始化:zend_long n = 1;,否则未传参时是随机栈值 - 返回动态分配的字符串时,别直接
RETURN_STRINGL(emalloc(...), len, 0)——0表示不复制,但内存没释放,下次调用就泄漏
RETURN_* 宏不是 printf,类型和生命周期必须手动管
RETURN_STRING、RETURN_LONG 这些宏只负责把值塞进 return_value zval,并不管理内存。C 层分配的资源,C 层必须清理。
- 用
emalloc分配的字符串,返回前必须efree,或改用RETURN_STRINGL(str, len, 1)(第三个参数为 1 表示复制并托管) - 操作
zval前先ZVAL_DEREF解引用,尤其当 PHP 传入的是引用变量,否则修改的是副本 - 读取
zval值必须用宏:Z_STRVAL_P、Z_LVAL_P,不能直接访问zval->value.lval——联合体偏移随 PHP 版本变,宏已做适配 - 新分配
zval必须初始化:zval tmp; ZVAL_NULL(&tmp);,未初始化的zval的u1.v.type是垃圾值,Z_TYPE_P判断会失效
config.m4 不只是“开关”,它决定扩展能否被正确链接
config.m4 是 Unix-like 平台下 ./configure 脚本的源头,写错会导致扩展编译通过但加载失败,或符号找不到。
立即学习“PHP免费学习笔记(深入)”;
-
PHP_ARG_ENABLE的扩展名必须和zend_module_entry中的名称一致,比如"myext",否则extension=myext.so在 php.ini 里不生效 -
PHP_NEW_EXTENSION(myext, myext.c, $ext_shared)第二个参数是源文件列表,多个文件用空格分隔,不能写成myext.c myext_util.c却漏掉myext_util.c的声明 - 若扩展依赖外部库(如
-lcurl),必须在config.m4里用AC_CHECK_LIB检查,并在PHP_ADD_LIBRARY_WITH_PATH中追加链接选项,否则make成功但dlopen失败 - PHP 8.7 要求
zend_module_entry中的min_php_version字段必须显式设为"8.7.0",否则内核拒绝加载,报错Extension 'myext' requires at least PHP version 8.7.0
实际写一个函数,最常被忽略的是:你写的 C 函数签名、参数解析、返回值处理、内存释放这四步必须闭环。少一步,轻则返回 NULL,重则进程崩溃。而 config.m4 和模块入口结构,不是“写对就行”,是“必须和 php-config 输出、目标 PHP 版本、构建工具链三者咬合”。









