PHP-X
是我在2017
年年初建立的一个新项目。这个项目的目标就是让有必定工做经验的PHP
程序都可以具有扩展开发的能力。php
从2012
年开始编写swoole
,如今算来已经有5
个年头了。我发现编写一个 PHP 扩展这个工做很是艰难。PHP 程序员群体中,甚至能够说 100 人中都很难找出一个会编写 PHP 扩展的人来。PHP 官方对扩展开发者很是不友好,源代码中提供的Zend API
极其难用,API
复杂并且凌乱,充斥着各类宏的写法。Zend API
坑很是多,普通开发者很容易踩到坑里。出现各类莫名其妙的core dump
问题。Zend API
几乎没有任何文档,开发者若是要真正掌握这项技能须要付出大量的学习时间。mysql
因而我今年就冒出一个新的想法,基于我编写swoole
扩展超过5
年的经验,我试图在Zend API
和C++
之间创建一个包装层,让PHP
扩展开发变得简单。有必定C++
基础的PHPer
均可以轻松得开发一个PHP
扩展。c++
PHP-X
这个项目就这样诞生了,开发只用了一个月的时间。它的开发效率很是高,在我公司中一个只工做了3
年的 PHP 程序员,均可以作出一个扩展来。接下来陆续在公司的几个项目中进行了快速验证。在3
个的时间里修复了大量崩溃和内存泄漏问题。目前稳定性、性能、健壮性均已达到工业级水准。git
PHP-X
自己基于C++11
开发,使用cmake
进行编译配置。首先,你须要肯定全部依赖项已安装好。包括:程序员
php7-dev
包而后安装PHP-X
。github
git clone https://github.com/swoole/PHP-X.git cd PHP-X cmake . make -j 4 sudo make install
未出现任何编译错误,会成功编译出libphpx.so
,并安装到系统的lib
目录。头文件会复制到系统的include
目录。这时须要执行 sudo ldconfig
刷新so
文件缓存。redis
使用任意开发工具,新建一个test.cc
源文件。首先须要引入phpx.h
头文件。而后使用using
引入phpx
的命名空间。PHP
官方未使用C++
,所以phpx
直接使用了php
做为命名空间。sql
#include <phpx.h> using namespace std; using namespace php;
建立扩展使用PHPX_EXTENSION
宏来实现。在这宏中只须要new Extension
便可建立扩展。构造方法接受2
个参数,第一个是扩展的名称,第二个是扩展的版本号。在PHPX_EXTENSION
宏中return
这个扩展对象的指针。mongodb
PHPX_EXTENSION() { Extension *ext = new Extension("test", "0.0.1"); return ext; }
这里必须使用
new Extension
,而不能直接在栈上建立对象shell
一个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
的数组。
#include <phpx.h> using namespace std; using namespace php; //声明函数 PHPX_FUNCTION(cpp_test); PHPX_EXTENSION() { Extension *ext = new Extension("test", "0.0.1"); ext->registerFunction(PHPX_FN(cpp_test)); return ext; } //实现函数 PHPX_FUNCTION(cpp_test) { //args[1] 就是这个扩展函数的第 2 个参数 long n = args[1].toInt(); //将返回值 retval 初始化为数组 Array _array(retval); for(int i = 0; i < n; i++) { //args[0] 就是这个扩展函数的第 1 个参数 //append 方法表示向数组中追加元素 _array.append(args[0]); } }
编写一个Makefile
文件。内容以下:
PHP_INCLUDE = `php-config --includes` PHP_LIBS = `php-config --libs` PHP_LDFLAGS = `php-config --ldflags` PHP_INCLUDE_DIR = `php-config --include-dir` PHP_EXTENSION_DIR = `php-config --extension-dir` test.so: test.cc c++ -DHAVE_CONFIG_H -g -o test.so -O0 -fPIC -shared test.cc -std=c++11 ${PHP_INCLUDE} -I${PHP_INCLUDE_DIR} -lphpx install: test.so cp test.so ${PHP_EXTENSION_DIR}/ clean: rm *.so
php-config
这个工具是PHP
提供的,使用php-config
能够获得PHP
的安装路径、头文件目录、扩展目录、其余额外的编译参数等等。
这个Makefile
支持了3
个指令,make
编译,make clean
清理,make install
安装到扩展目录中。
这里可能须要
root
权限,使用sudo make install
进行安装
直接从网页复制,可能会出现tab
制表符被替换为空格,请手工编辑一下Makefile
使用tab
缩进MacOS
下须要在c++
编译参数中增长-undefined dynamic_lookup
编写好以后执行make install
,就会编译扩展并将扩展test.so
安装到PHP
的扩展目录中。这时须要修改php.ini
加入extension=test.so
加载扩展。
使用php -m
来观察你的扩展是否正常加载。
php -m [PHP Modules] Core ctype curl date dom fileinfo filter gd hash iconv inotify json libxml mbstring mcrypt memcached mongodb mysqli mysqlnd openssl pcntl pcre PDO pdo_mysql pdo_sqlite Phar posix redis Reflection session SimpleXML sockets SPL sqlite3 standard swoole test tokenizer xml xmlreader xmlwriter yac zlib zmq [Zend Modules]
这里看到test
,代表你的扩展已经加载成功了,如今就能够调用cpp_test
这个扩展函数了。
编写一个test.php
,内容为:
<?php var_dump(cpp_test("hello", 3));
执行test.php
:
php test.php array(3) { [0]=> string(5) "hello" [1]=> string(5) "hello" [2]=> string(5) "hello" }
能够看到执行结果符合预期。那么恭喜你,如今你已经成功地开发了一个PHP
扩展了。是否是很简单?
上面的例子还比较简单,只是编写了一个扩展函数。要真正在实际项目中使用PHP-X
你还有不少工做要作。
C++
的功底PHP-X
的 API 另外配合使用Eclipse
等IDE
工具,能够实现API
自动提示和补齐,开发起来会更顺手。
相比Zend API
,PHP-X
要简单易用地多了,相信你不会花太多时间就能够掌握此项技能。在接下来我会撰写更多教程,教你们如何使用PHP-X
实现扩展类、资源、回调函数等更复杂的功能。