“深入实战:使用BPC编译器编译 PHP 项目 workerman/GatewayWorker”

BPC 可以将 PHP 代码最终转译成 C 语言,然后编译成动态链接库或者可执行程序,实现 PHP Native AOT.

图片[1]-“深入实战:使用BPC编译器编译 PHP 项目 workerman/GatewayWorker”-山海云端论坛
  1. 背景
    最近在做一个招聘求职类的项目,B 端 HR 使用的是云招 OurATS 招聘管理系统,C 端求职者使用的是微信小程序.

HR 在 B 端创建的职位会显示在微信小程序上,求职者在小程序上可以浏览职位信息,就某职位和 HR 在线聊天沟通.

求职者投递简历后,也可以就此次投递和 HR 在线聊天沟通.

其中在线聊天功能是基于 workerman/GatewayWorker 实现的.

整个项目 (OurATS + 小程序后端 + 在线聊天) 都使用 PHP 开发,交付给客户时,经 BPC 编译成.so 和 elf 可执行文件部署到客户的服务器上.

虽然之前就尝试着编译过 workerman, 但毕竟不是真刀真枪的项目,$eventLoopClass 用的还是 Select.

借着这个在线聊天的机会,BPC 实现了 event(core) 扩展,针对 BPC 调整了部分 workerman/GatewayWorker 的代码,把 BPC 编译版本的 workerman/GatewayWorker 推向生产环境.

  1. PHP 编译器 BPC 用前须知
    BPC target 的目标是 php 7.2, 更精确地说是 php 7.2.19
    测试用例参看 bpc-php-7.2.19-tests
    BPC 不支持的语法特性可以使用 phptobpc 进行转换,如果 phptobpc 也不支持,那就只能修改你的代码或者等待 BPC 升级了.
    BPC 当前不支持的扩展一般不是大问题,因为 BPC 的扩展开发是比较容易的.
    目前 BPC 及其编译产物仅在 ubuntu 18.04 amd64 上完善测试过,在其它 linux 发行版上有可能能运行,大概率会遇到问题。但这并不是说 BPC 无法在其它发行版上运行,我曾在自己的 CubieBoard 7 上的 debian stretch 系统下成功编译并跑通了 phpt 测试.
  2. BPC 支持编译的 workerman/GatewayWorker 版本
    workerman

workerman 在 5.0 新版本中引入了 Typed Properties 特性。也就是如下代码:

图片[2]-“深入实战:使用BPC编译器编译 PHP 项目 workerman/GatewayWorker”-山海云端论坛

BPC 目前不支持这一特性,所以不支持编译 workerman 5.0 版本.

BPC 当前调整好的,可以编译,基本测试没问题的版本是 workerman 4.1 版本.

Gatewayworker

GatewayWorker master 分支引入了 class method 的返回类型。也就是如下代码:

图片[3]-“深入实战:使用BPC编译器编译 PHP 项目 workerman/GatewayWorker”-山海云端论坛

BPC 目前不支持这一特性,所以不支持编译 GatewayWorker master 分支.

BPC 当前调整好的,可以编译,基本测试没问题的版本是 GatewayWorker 3.x 分支.

  1. 为了能够成功编译,需要对 workerman/GatewayWorker 源码做哪些调整?
    workerman

在编译的场景下,DIR 的语义发生了变化,所以涉及到读写文件的DIR都需要调整一下.

BPC 不支持 STREAM_CLIENT_ASYNC_CONNECT, 所以不能用 AsyncTcpConnection.php. 我写了一个 SyncTcpConnection.php 来替代 AsyncTcpConnection.php, 两者的区别在于最开始建立连接是同步还是异步,其它都一样.

BPC 实现的__destruct() 不适用于 workerman 这种需要长时间运行的程序,所以有 __destruct() 方法的类都做了调整.

BPC 实现的 event 扩展对于长期运行的程序需要手动 free event, 所以对 Events/Event.php 做了调整.

大的调整就这 4 点,具体细节可以查看 github commits.

GatewayWorker

用到 AsyncTcpConnection 的地方都换成了 SyncTcpConnection

BPC 不支持 class_alias, 所以代码中的 class_alias(‘GatewayWorker\Protocols\GatewayProtocol’, ‘Protocols\GatewayProtocol’); 都去掉了,需要在自己的项目里加一个如下的 class.

图片[4]-“深入实战:使用BPC编译器编译 PHP 项目 workerman/GatewayWorker”-山海云端论坛

BPC 实现的 pdo 扩展对于长期运行的程序需要明确的调用 $pdo->closeConnection() 和 $stmt->destroy(), 所以对 src/Lib/DbConnection.php 做了调整.

大的调整就这 3 点,具体细节可以查看 github commits.

  1. 怎么编译 workerman 4.1 和 GatewayWorker 3.x ?
    首先需要安装 bpc-compiler 和 phptobpc
图片[5]-“深入实战:使用BPC编译器编译 PHP 项目 workerman/GatewayWorker”-山海云端论坛
图片[6]-“深入实战:使用BPC编译器编译 PHP 项目 workerman/GatewayWorker”-山海云端论坛

现在 workerman 和 gatewaywoker 已经被编译成 .so 和 .a 并安装到 /usr/local/lib 目录下了.

接下来在编译 workerman 和 GatewayWorker 应用时只需要给 bpc 加上 -u workerman -u gatewayworker 就可以了.

关于 BPC 的高级用法请看 Wiki: 05_Advanced_usage.

  1. 在 BPC Playground 里立即尝试
    bpc.dev Try it online (BPC Playground) 里已经加上了 workerman 和 GatewayWorker 示例.

不想自己安装编译环境的可以使用这个 online compiler 立即尝试编译 workerman 和 GatewayWorker 应用.

图片[7]-“深入实战:使用BPC编译器编译 PHP 项目 workerman/GatewayWorker”-山海云端论坛
图片[8]-“深入实战:使用BPC编译器编译 PHP 项目 workerman/GatewayWorker”-山海云端论坛
© 版权声明
THE END
喜欢就支持一下吧
点赞9 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容