专栏名称: SegmentFault思否
SegmentFault (www.sf.gg)开发者社区,是中国年轻开发者喜爱的极客社区,我们为开发者提供最纯粹的技术交流和分享平台。
目录
相关文章推荐
待字闺中  ·  DeepSeek“七问”李国杰院士 ·  14 小时前  
程序员小灰  ·  小灰筹划6年的“仓鼠币系统”,终于上线了! ·  2 天前  
程序员的那些事  ·  GPU:DeepSeek ... ·  昨天  
OSC开源社区  ·  RAG市场的2024:随需而变,从狂热到理性 ·  2 天前  
程序员的那些事  ·  印度把 DeepSeek ... ·  4 天前  
51好读  ›  专栏  ›  SegmentFault思否

如何基于 PHP-X 快速开发一个 PHP 扩展

SegmentFault思否  · 公众号  · 程序员  · 2017-09-15 08:00

正文

PHP-X 是我在 2017 年年初创建的一个新项目。这个项目的目标就是 让有一定工作经验的 PHP 程序都能够具备扩展开发的能力

0x00 初衷

2012 年开始编写 swoole ,现在算来已经有 5 个年头了。我发现编写一个 PHP 扩展这个工作非常艰难。PHP 程序员群体中,甚至可以说 100 人中都很难找出一个会编写 PHP 扩展的人来。PHP 官方对扩展开发者非常不友好,源代码中提供的 ZendAPI 极其难用, API 复杂而且凌乱,充斥着各种宏的写法。 ZendAPI 坑非常多,普通开发者很容易踩到坑里。出现各种莫名其妙的 coredump 问题。 ZendAPI 几乎没有任何文档,开发者如果要真正掌握这项技能需要付出大量的学习时间。

于是我今年就冒出一个新的想法,基于我编写 swoole 扩展超过 5 年的经验,我试图在 ZendAPI C++ 之间建立一个包装层,让 PHP 扩展开发变得简单。有一定 C++ 基础的 PHPer 都可以轻松得开发一个 PHP 扩展。

PHP-X 这个项目就这样诞生了,开发只用了一个月的时间。它的开发效率非常高,在我公司中一个只工作了 3 年的 PHP 程序员,都可以做出一个扩展来。接下来陆续在公司的几个项目中进行了快速验证。在 3 个的时间里修复了大量崩溃和内存泄漏问题。目前稳定性、性能、健壮性均已达到工业级水准。

0x01 起步

PHP-X 本身基于 C++11 开发,使用 cmake 进行编译配置。首先,你需要确定所有依赖项已安装好。包括:

  • gcc-4.8 或更高版本

  • php-7.0 或更高版本,需要 php7-dev

  • cmake-2.8 或更高版本

然后安装 PHP-X

  1. git clone https://github.com/swoole/PHP-X.git

  2. cd PHP-X

  3. cmake .

  4. make -j 4

  5. sudo make install

未出现任何编译错误,会成功编译出 libphpx.so ,并安装到系统的 lib 目录。头文件会复制到系统的 include 目录。这时需要执行 sudo ldconfig 刷新 so 文件缓存。

0x02 新建工程

使用任意开发工具,新建一个 test.cc 源文件。首先需要引入 phpx.h 头文件。然后使用 using 引入 phpx 的命名空间。 PHP 官方未使用 C++ ,因此 phpx 直接使用了 php 作为命名空间。

  1. #include

  2. using namespace std;

  3. using namespace php;

创建扩展使用 PHPX_EXTENSION 宏来实现。在这宏中只需要 newExtension 即可创建扩展。构造方法接受 2 个参数,第一个是扩展的名称,第二个是扩展的版本号。在 PHPX_EXTENSION 宏中 return 这个扩展对象的指针。

  1. PHPX_EXTENSION()

  2. {

  3.    Extension *ext = new Extension("test", "0.0.1");

  4.    return ext;

  5. }

这里必须使用 newExtension ,而不能直接在栈上创建对象

0x03 增加函数

一个 PHP 扩展的主要作用就是提供扩展函数,扩展函数由于是用 C/C++ 代码实现,因此它的性能会比 PHP 用户函数性能高几十甚至上百倍。在 phpx 中实现函数非常简单。使用 PHPX_FUNCTION 来实现扩展函数,然后调用 Extension::registerFunction 来注册扩展函数。

PHPX_FN 是一个助手宏,实际上展开就是 "cpp_hello_world",cpp_hello_world
PHPX_FUNCTION 展开后,包含了 2 个变量,第一个是参数 args ,第二个是返回值 retval
通过操作 args retval 两个变量,就可以实现函数的输入和输出

这里我们的代码非常简单, cpp_test($str,$n) ,调用这个函数返回一个 $n $str 的数组。

  1. #include

  2. using namespace std;

  3. using namespace php;

  4. //声明函数

  5. PHPX_FUNCTION(cpp_test);

  6. PHPX_EXTENSION()

  7. {

  8.    Extension *ext = new Extension("test", "0.0.1");

  9.    ext->registerFunction(PHPX_FN(cpp_test));

  10.    return ext;

  11. }

  12. //实现函数

  13. PHPX_FUNCTION(cpp_test)

  14. {

  15.    //args[1] 就是这个扩展函数的第 2 个参数

  16.    long n = args[1].toInt();

  17.    //将返回值 retval 初始化为数组

  18.    Array _array(retval);

  19.    for(int i = 0; i < n; i++)

  20.    {

  21.        //args[0] 就是这个扩展函数的第 1 个参数

  22.        //append 方法表示向数组中追加元素

  23.        _array.append(args[0]);

  24.    }

  25. }

0x04 编译扩展

编写一个 Makefile 文件。内容如下:

  1. PHP_INCLUDE = `php-config --includes`

  2. PHP_LIBS = `php-config --libs`

  3. PHP_LDFLAGS = `php-config --ldflags`

  4. PHP_INCLUDE_DIR = `php-config --include-dir`

  5. PHP_EXTENSION_DIR = `php-config --extension-dir`

  6. test.so: test.cc

  7.    c++ -DHAVE_CONFIG_H -g -o test.so -O0 -fPIC -shared test.cc -std=c++11 ${PHP_INCLUDE} -I${PHP_INCLUDE_DIR} -lphpx

  8. install: test.so

  9.    cp test.so ${PHP_EXTENSION_DIR}/

  10. clean:

  11.    rm *.so

php-config 这个工具是 PHP 提供的,使用 php-config 可以得到 PHP 的安装路径、头文件目录、扩展目录、其他额外的编译参数等等。

这个 Makefile 支持了 3 个指令, make 编译, make clean 清理, make install 安装到扩展目录中。

这里可能需要 root 权限,使用 sudo make install 进行安装
直接从网页复制,可能会出现 tab 制表符被替换为空格,请手工编辑一下 Makefile 使用 tab 缩进
MacOS 下需要在 c++ 编译参数中增加 -undefineddynamic_lookup

编写好之后执行 make install ,就会编译扩展并将扩展 test.so 安装到 PHP 的扩展目录中。这时需要修改 php.ini 加入 extension=test.so 加载扩展。

使用 php-m 来观察你的扩展是否正常加载。

  1. php -m

  2. [PHP Modules]

  3. Core

  4. ctype

  5. curl

  6. date

  7. dom

  8. fileinfo

  9. filter

  10. gd

  11. hash

  12. iconv

  13. inotify

  14. json

  15. libxml

  16. mbstring

  17. mcrypt

  18. memcached

  19. mongodb

  20. mysqli

  21. mysqlnd

  22. openssl

  23. pcntl

  24. pcre

  25. PDO

  26. pdo_mysql







请到「今天看啥」查看全文