PHP编译器BPC编译实战: workerman/GatewayWorker

heguangyu5

不了解BPC是什么的可以翻看之前的贴子.

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

how BPC works

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 推向生产环境.

2. PHP编译器BPC用前须知

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

3. BPC支持编译的 workerman/GatewayWorker 版本

workerman

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

class Worker 
{
    public int $id = 0; // 注意 public 和 $id 中间的 int
}

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

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

Gatewayworker

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

class BusinessWorker extends Worker
{
    public function run(): void // 注意 run() 后边的 : void
    {}
}

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

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

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

workerman

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

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

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

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

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

GatewayWorker

  1. 用到 AsyncTcpConnection 的地方都换成了 SyncTcpConnection

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

    <?php
    namespace Protocols;
    class GatewayProtocol extends \GatewayWorker\Protocols\GatewayProtocol
    {}
  3. BPC实现的pdo扩展对于长期运行的程序需要明确的调用 $pdo->closeConnection()$stmt->destroy(), 所以对 src/Lib/DbConnection.php 做了调整.

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

5. 怎么编译 workerman 4.1 和 GatewayWorker 3.x ?

  1. 首先需要安装 bpc-compilerphptobpc

  2. git clone git@github.com:bob-php-compiler/bpc-workerman-4.1-branch.git
    cd bpc-workerman-4.1-branch
    make
    cd Workerman
    sudo bpc -l workerman --install
  3. git clone git@github.com:bob-php-compiler/bpc-GatewayWorker-3.x-branch.git
    cd bpc-GatewayWorker-3.x-branch/src
    make
    cd ../GatewayWorker
    sudo bpc -l gatewayworker --install

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

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

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

6. 在 BPC Playground 里立即尝试

https://bpc.dev Try it online (BPC Playground) 里已经加上了 workerman 和 GatewayWorker 示例.

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

workerman.png

GatewayWorker.png

1371 4 1
4个评论

happy321

谢谢 建议多优化workerman PHP源码加密就靠你这个项目啦

  • 暂无评论
JackDx

关注

  • 暂无评论
sanye

6666

  • 暂无评论
songshu

你这完全可以做成一个插件了,估计用的人还蛮多

  • 暂无评论

heguangyu5

2100
积分
0
获赞数
0
粉丝数
2022-11-24 加入
×
🔝