Windows 环境下开发并编译 PHP C 扩展完整指南
在 Windows 环境中为 PHP 编写自定义 C 扩展,需要结合 Visual Studio (VC++)、Cygwin 以及 PHP 源代码树进行构建。通过配置编译器路径、利用 ext_skel 脚本快速搭建骨架、调整工程链接选项,即可生成可用于生产环境的 .dll 动态库。本文将逐步拆解从准备环境到最终加载扩展的各个环节。
开发环境准备
要成功编译 PHP 扩展,必须确保计算机上安装了以下基础组件,并正确设置了相关路径:
- Cygwin:用于提供 make 等类 Unix 工具链。假设安装路径为
e:\app\cygwin。 - Visual Studio C++:推荐使用稳定的版本(如 VS 2010/2012/2015 等较新版本,原文提及的 VS6 已过时且不再支持现代 SDK)。需安装对应的 C/C++ 编译器组件。
- PHP 源代码包:下载与您目标运行版本一致的 PHP 源码包。假设解压目录为
e:\c_source_code\php-5.2.5。注意:源码版本需与您本地安装的 PHP 大版本保持一致。 - PHP 二进制目录:将已安装的 PHP 路径(例如
e:\app\php5.2.5)添加到系统的环境变量PATH中,以便命令行能直接调用php.exe。
第一步:配置骨架生成器路径
PHP 源码中提供了一个名为 ext_skel_win32.php 的辅助脚本,用于自动生成本地扩展的文件结构。首先需要修改该脚本以指向正确的 Cygwin 路径。
- 打开文件:
PHP源文件目录/ext/ext_skel_win32.php(例如E:\c_source_code\php-x.x.x\ext\ext_skel_win32.php)。 - 找到定义 Cygwin 路径的变量
$cygwin_path,将其修改为您的实际安装路径:
$cygwin_path = 'e:\app\cygwin\bin'; // 请根据实际路径修改
第二步:生成扩展骨架代码
在 ext 目录下执行骨架生成命令。此步骤会创建一个新的文件夹,包含扩展的基本文件结构和头文件。
- 打开命令行终端,进入
e:\c_source_code\php-x.x.x\ext目录。 - 运行命令:
php ext_skel_win32.php --extname=foo
执行成功后,会在当前目录下生成一个名为 foo 的新目录,其中包含了 config.w32.h、foo.c、foo.def 等必要文件。
第三步:添加链接库文件
为了让生成的扩展能够正确链接 PHP 的核心函数,需要将 PHP 运行时库拷贝到扩展目录中。
- 找到 PHP 源码或安装目录下的
dev文件夹。 - 将
php5ts.lib(对应线程安全版)或php5ts.lib(根据您的 php.ini 配置选择)复制到刚创建的ext/foo目录中。
第四步:编写扩展业务逻辑
使用编辑器打开 ext/foo/foo.c 文件。这是扩展的主要实现文件。您可以在其中:
- 查找注释标记位置(通常提示在哪里添加用户自定义函数)。
- 使用
PHP_FUNCTION(foo)宏声明新的 PHP 可调用的函数。 - 在
foo_methods[]数组中添加函数的方法定义映射。
此处需要根据实际需求填充具体的 C 语言代码逻辑。
第五步:配置 Visual Studio 工程
这一步是将 C 代码编译为 DLL 的关键。请使用 Visual Studio 打开对应的工程文件(通常为 .dsp 格式或使用新式解决方案文件的 .vcxproj)。
- 打开工程:进入
ext/foo目录,用 VC++ 打开foo.dsp或相应的工程文件。 - 调整工程配置:
- 点击菜单 组建 (Build) → 移除工程配置 (Remove Configuration)。
- 取消勾选 Win 32 Debug_TS(如果不需要调试)或保持 Win 32 Release_TS 作为活动配置。建议统一使用 Release_TS(Thread Safe Release)以保证性能与稳定性。
- 在菜单栏选择 工程 (Project) → 设置 (Settings)(旧版 VC)或在属性页中选择 Win 32 Release_TS。
- 配置链接器参数:
- 切换到 连接 (Link) 标签页。
- 在“输出文件名”一栏,确认输出路径和名称(默认应为
foo.dll)。
- 配置预处理器定义:
- 切换到 C/C++ 标签页。
- 在“预处理器定义”中,增加
COMPILE_DL_FOO(注意全大写,且末尾替换为您的扩展名,例如COMPILE_DL_BAR)。这告诉 PHP 扩展的动态链接机制。 - 关键操作:务必取消选中
ZEND_DEBUG或类似影响 ZEND 宏定义的选项(原文提到的LIBZEND_EXPORTS是旧版概念,在新版 SDK 中通常涉及避免符号冲突的配置,若遇到 undefined reference to ZEND 相关错误,需检查 include 路径是否包含正确的ZEND_API定义)。更通用的做法是确保在 Release 模式下不导出 PHP 内部符号,仅导入。
风险提示:编译前的环境配置至关重要。若 VC++ 找不到 php.h 或 zend.h,请务必在 IDE 的“包含目录”中加入 PHP 源码的根目录及 main、Zend 子目录。错误的配置会导致大量链接错误。
第六步:编译与验证
完成上述设置后,执行编译操作(Build Solution)。若一切顺利,将在输出目录生成 foo.dll 文件。
- 部署 DLL:将生成的
foo.dll复制到您 PHP 环境的扩展目录下(例如e:\app\ext)。 - 配置 php.ini:打开
php.ini文件,在扩展部分添加一行:
extension=foo.dll
- 重启服务:重启 Apache/IIS 或 php-fpm 进程。
- 验证:访问
phpinfo()页面。如果在列表中找到foo扩展及其版本信息,说明扩展已成功加载。您现在可以在 PHP 代码中直接使用foo()函数了。
常见问题排查
- L1081 Error**: 如果链接出现 L1081 错误,通常是.lib 文件路径错误或版本号不匹配。请确保拷贝的是与 PHP 版本完全一致的
php5ts.lib。 - Undefined symbols**: 若提示 Zend API 未定义,请检查 VC++ 附加包含目录是否正确指向了 PHP 源码根目录。
- 编码问题**: PHP 源码中的 C 文件通常使用 UTF-8 without BOM 编码。若在中文 Windows 上使用记事本编辑,请确保另存为 UTF-8 格式,以免引入乱码字符导致编译失败。
以上就是 Windows 下开发并编译 PHP 扩展的详细操作过程。通过规范的工程配置和骨架脚本,开发者可以高效地构建自定义功能模块。更多关于 PHP 底层开发和扩展优化的技术文章,请关注本站其他相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









