ext_skel是php官方提供的扩展骨架生成工具,必须在php源码ext/目录下运行,可自动生成config.m4、php_myext.h、myext.c等核心文件,并需配合phpize构建流程完成编译安装。

phpize 是你真正动手前绕不开的第一道门——没它,连骨架都搭不起来。
从 ext_skel 生成骨架开始,别手写 config.m4
很多人一上来就手动建 .c 文件、硬啃 zend_module_entry 结构体,结果卡在编译报错“undefined symbol”上。实际开发中,PHP 官方提供的 ext_skel 工具能自动生成完整骨架,包括 config.m4、php_myext.h、myext.c 和基础模块声明。
-
ext_skel必须在 PHP 源码的ext/目录下运行(不是你自己的项目目录) - 生成后要立刻检查
config.m4:确认PHP_NEW_EXTENSION行里第三个参数是$ext_shared,否则make install后得不到 .so 文件 - 不要删掉
PHP_FE宏里的NULL占位符——少一个就会导致函数表解析失败,extension_loaded()返回 true,但调用函数时直接Fatal error: Uncaught Error: Call to undefined function
编译链必须用 phpize → ./configure → make → make install
跳过 phpize 直接 ./configure 会报 “Can’t find PHP headers”,因为 configure 脚本依赖 phpize 生成的 configure.in 和 buildconf 脚本。而用系统默认的 autotools 手动构建,大概率链接到错误的 Zend API 版本,导致扩展加载时 segfault。
-
phpize必须指向你要适配的 PHP 版本,比如/usr/bin/phpize8.2或$(which phpize)(确认php -v和phpize -v主版本一致) -
./configure --enable-myext中的--enable-前缀必须和config.m4里PHP_ARG_ENABLE的第一个参数完全一致,大小写敏感 -
make install输出的路径(如/usr/lib/php/20220829/)要记下来,后面php.ini里extension=的值得匹配这个目录下的文件名
调试阶段优先用 php_printf + strace,别急着上 gdb
扩展一加载就崩溃,90% 不是逻辑错,而是内存越界或引用计数异常。这时候 gdb 断点往往还没进到你的函数就挂了。先用最轻量的方式定位:
- 在
PHP_MINIT_FUNCTION开头加php_printf("MINIT called\n");,然后php -m | grep myext看是否输出——没输出说明模块注册失败;有输出但后续函数调用失败,说明函数表或参数解析出问题 - 用
strace -e trace=openat,open,openat64 php -r "myext_do();"观察是否成功 open() 到 .so 文件,以及是否因找不到依赖(如 libc、libz)而失败 - 避免在函数里用
printf或std::cout:它们不走 PHP 的输出缓冲,可能乱序、丢失,甚至触发线程竞争
参数解析必须用 ZEND_PARSE_PARAMETERS_START 宏,别手写 Z_PARAM_*
PHP 8+ 强制要求使用新版参数解析宏,否则编译通过但运行时报 Segmentation fault (core dumped)。旧式 ZEND_ARG_INFO + 手动 zend_parse_parameters 在 PHP 8.0+ 已被标记为废弃,且不校验类型严格性。
- PHP 7.4 及以下可用
zend_parse_parameters,但必须配合RETURN_FALSE/RETURN_TRUE显式返回,不能只写return; - PHP 8.0+ 必须用
ZEND_PARSE_PARAMETERS_START(1, 2)包裹,且每个Z_PARAM_*后必须跟对应变量地址,比如Z_PARAM_STR(str)对应zend_string *str - 接收字符串参数时,
zend_string *比char *更安全:前者自带长度,避免strlen()遇到 \0 截断;后者需额外传size_t长度参数,极易漏写
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











