TypePHP 编译器
https://swoole.com/aot/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
8.8 KiB
8.8 KiB
PHP AOT 编译器编译模式详解
📋 概述
PHP AOT 编译器支持两种编译模式,每种模式针对不同的使用场景。本文档详细说明两种模式的区别、使用方法和最佳实践。
🔹 扩展模式 (Extension Mode)
基本概念
扩展模式将 PHP 代码编译为 PHP 扩展文件(.so 或 .dll),可以作为标准 PHP 扩展加载到 php-fpm 中运行。
编译命令
php bin/tpc.php <source_dir> --mode=ext -o <output_name>
示例
# 编译 Coolify 项目
php bin/tpc.php projects/coolify/app/ --mode=ext -o coolify
# 输出文件
coolify.so # Linux
coolify.dll # Windows
安装方法
1. 临时加载(测试用)
php -d extension=./coolify.so -r "echo 'Extension loaded';"
2. 永久加载(生产环境)
# 复制扩展文件到 PHP 扩展目录
sudo cp coolify.so $(php-config --extension-dir)/
# 创建配置文件
echo "extension=coolify" | sudo tee /etc/php/8.1/mods-available/coolify.ini
# 启用扩展
sudo phpenmod coolify
# 重启 PHP-FPM
sudo systemctl restart php8.1-fpm
代码结构
不需要 main() 函数
<?php
// 定义类
class UserController {
public function index() {
return "User List";
}
}
// 定义函数
function route_handler($path) {
echo "Handling: {$path}";
}
// 扩展模式下,这些代码会在被 PHP 调用时执行
// 不需要 main() 函数
使用场景
✅ 适合:
- Web 应用程序
- API 服务
- 需要与现有 PHP 框架集成
- 依赖 php-fpm 的生产环境
- SaaS 平台
❌ 不适合:
- 命令行工具
- 独立运行的服务
- 长期驻留的守护进程
优点
| 优点 | 说明 |
|---|---|
| 🔒 安全性 | 源码被编译,不易泄露 |
| ⚡ 性能 | 比纯 PHP 快 3-10 倍 |
| 🔄 兼容性 | 完全兼容现有 PHP 生态 |
| 📦 易部署 | 标准的 PHP 扩展安装方式 |
缺点
| 缺点 | 说明 |
|---|---|
| 🔧 依赖 PHP | 需要 PHP 运行时环境 |
| 🌐 仅限 Web | 主要面向 Web 场景 |
| ⚙️ 配置复杂 | 需要配置 PHP 扩展 |
🔸 二进制模式 (Binary Mode)
基本概念
二进制模式将 PHP 代码编译为独立的可执行文件,不依赖 PHP 运行时环境。
编译命令
php bin/tpc.php <source_dir> -o <output_binary>
示例
# 编译 Workerman 项目
php bin/tpc.php projects/workerman/src/ -o workerman
# 输出文件
workerman # Linux 可执行文件
运行方法
# 直接运行
./workerman start
# 后台运行
./workerman start -d
# 查看状态
./workerman status
代码结构
必须有 main() 函数
<?php
// 类定义
class Application {
public function run() {
echo "Application running\n";
}
}
// ✅ 必须定义 main() 函数
function main() {
$app = new Application();
$app->run();
}
// ✅ 或者带参数的 main()
function main(int $argc, array $argv) {
echo "Arguments: " . implode(', ', $argv) . "\n";
$app = new Application();
$app->run();
}
main() 函数签名
方式一:无参数(默认)
function main() {
// 程序入口
}
方式二:带命令行参数
function main(int $argc, array $argv) {
// $argc: 参数个数
// $argv: 参数数组
echo "Script: {$argv[0]}\n";
if ($argc > 1) {
echo "Arguments: " . implode(', ', array_slice($argv, 1)) . "\n";
}
}
使用场景
✅ 适合:
- 命令行工具(CLI)
- 长期运行的服务(如 Workerman)
- 微服务架构中的服务节点
- 独立应用程序
- 批处理任务
❌ 不适合:
- Web 应用(无法在浏览器中访问)
- 需要与现有 PHP 代码混合运行的场景
优点
| 优点 | 说明 |
|---|---|
| 🚀 零依赖 | 无需安装 PHP |
| 📦 易分发 | 单个可执行文件 |
| 🔐 安全性 | 完全编译为机器码 |
| ⚡ 高性能 | 优化的原生代码 |
缺点
| 缺点 | 说明 |
|---|---|
| 🖥️ 平台相关 | 需要为不同系统编译 |
| 🔄 更新复杂 | 需要重新编译和替换 |
| 🌐 不支持 Web | 无法在 php-fpm 中使用 |
📊 模式对比
详细对比表
| 特性 | 扩展模式 (--mode=ext) |
二进制模式 (默认) |
|---|---|---|
| 输出格式 | .so / .dll |
可执行文件 |
| 运行环境 | php-fpm / CLI | 独立运行 |
| PHP 依赖 | ✅ 需要 | ❌ 不需要 |
| main() 函数 | ❌ 不需要 | ✅ 必须 |
| Web 访问 | ✅ 支持 | ❌ 不支持 |
| CLI 运行 | ✅ 支持 | ✅ 支持 |
| 部署难度 | 中等 | 简单 |
| 性能提升 | 3-10 倍 | 5-20 倍 |
| 代码保护 | 中等 | 完全 |
| 适用场景 | Web 应用 | CLI 工具/服务 |
选择建议
需要运行在 Web 环境?
├─ 是 → 选择扩展模式
└─ 否 → 需要 main() 函数吗?
├─ 是 → 选择二进制模式
└─ 是 → 选择扩展模式
🎯 实战示例
示例一:Web API(扩展模式)
项目结构:
api-project/
├── src/
│ ├── Controllers/
│ │ └── UserController.php
│ ├── Routes.php
│ └── index.php
UserController.php:
<?php
namespace App\Controllers;
class UserController {
public function list() {
return [
['id' => 1, 'name' => 'Alice'],
['id' => 2, 'name' => 'Bob'],
];
}
}
index.php:
<?php
// 扩展模式:不需要 main()
use App\Controllers\UserController;
$controller = new UserController();
$data = $controller->list();
header('Content-Type: application/json');
echo json_encode($data);
编译:
php bin/tpc.php api-project/src/ --mode=ext -o api_extension
使用:
# 在 php-fpm 中作为扩展加载
# 通过 Web 服务器访问
示例二:CLI 工具(二进制模式)
项目结构:
cli-tool/
├── src/
│ ├── Command.php
│ └── main.php
Command.php:
<?php
class Command {
public function execute($args) {
echo "Executing with args: " . implode(' ', $args) . "\n";
}
}
main.php:
<?php
// 二进制模式:必须有 main()
function main(int $argc, array $argv) {
$command = new Command();
$command->execute(array_slice($argv, 1));
}
编译:
php bin/tpc.php cli-tool/src/ -o mytool
使用:
./mytool arg1 arg2 arg3
💡 最佳实践
扩展模式
-
命名空间: 使用唯一的命名空间避免冲突
namespace MyProject\Api; -
初始化: 提供扩展初始化函数
function init_extension() { // 初始化逻辑 } -
配置: 支持通过 php.ini 配置
ini_set('my_extension.enabled', '1');
二进制模式
-
错误处理: 在 main() 中处理全局异常
function main() { try { // 主逻辑 } catch (Throwable $e) { fwrite(STDERR, $e->getMessage()); exit(1); } } -
信号处理: 处理系统信号
function main() { pcntl_signal(SIGTERM, function() { echo "Shutting down...\n"; exit(0); }); // 主循环 } -
日志记录: 实现日志功能
function log_message($level, $message) { $timestamp = date('Y-m-d H:i:s'); echo "[{$timestamp}] [{$level}] {$message}\n"; }
🔍 故障排除
扩展模式问题
问题:扩展加载失败
PHP Warning: PHP Startup: Unable to load dynamic library
解决方案:
- 检查文件权限:
chmod 644 coolify.so - 验证 PHP 版本匹配:
php -v - 检查依赖:
ldd coolify.so
问题:Segmentation Fault
解决方案:
- 检查代码中是否使用了不支持的语法
- 查看错误日志:
tail -f /var/log/php/error.log - 使用 gdb 调试核心转储
二进制模式问题
问题:Permission denied
bash: ./myapp: Permission denied
解决方案:
chmod +x myapp
问题:找不到符号
error while loading shared libraries
解决方案:
# 设置库路径
export LD_LIBRARY_PATH=/path/to/libs:$LD_LIBRARY_PATH
# 检查实际链接路径和依赖
ldd ./app
📚 相关文档
最后更新: 2024 年 3 月 18 日
文档版本: v1.0