|
|
|
|
@ -0,0 +1,475 @@ |
|
|
|
|
# PHP AOT 编译器编译模式详解 |
|
|
|
|
|
|
|
|
|
## 📋 概述 |
|
|
|
|
|
|
|
|
|
PHP AOT 编译器支持两种编译模式,每种模式针对不同的使用场景。本文档详细说明两种模式的区别、使用方法和最佳实践。 |
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
## 🔹 扩展模式 (Extension Mode) |
|
|
|
|
|
|
|
|
|
### 基本概念 |
|
|
|
|
|
|
|
|
|
扩展模式将 PHP 代码编译为 PHP 扩展文件(`.so` 或 `.dll`),可以作为标准 PHP 扩展加载到 php-fpm 中运行。 |
|
|
|
|
|
|
|
|
|
### 编译命令 |
|
|
|
|
|
|
|
|
|
```bash |
|
|
|
|
php bin/compiler.php <source_dir> --mode=ext -o <output_name> |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
### 示例 |
|
|
|
|
|
|
|
|
|
```bash |
|
|
|
|
# 编译 Coolify 项目 |
|
|
|
|
php bin/compiler.php projects/coolify/app/ --mode=ext -o coolify |
|
|
|
|
|
|
|
|
|
# 输出文件 |
|
|
|
|
coolify.so # Linux |
|
|
|
|
coolify.dll # Windows |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
### 安装方法 |
|
|
|
|
|
|
|
|
|
#### 1. 临时加载(测试用) |
|
|
|
|
|
|
|
|
|
```bash |
|
|
|
|
php -d extension=./coolify.so -r "echo 'Extension loaded';" |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
#### 2. 永久加载(生产环境) |
|
|
|
|
|
|
|
|
|
```bash |
|
|
|
|
# 复制扩展文件到 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 |
|
|
|
|
<?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 运行时环境。 |
|
|
|
|
|
|
|
|
|
### 编译命令 |
|
|
|
|
|
|
|
|
|
```bash |
|
|
|
|
php bin/compiler.php <source_dir> -o <output_binary> |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
### 示例 |
|
|
|
|
|
|
|
|
|
```bash |
|
|
|
|
# 编译 Workerman 项目 |
|
|
|
|
php bin/compiler.php projects/workerman/src/ -o workerman |
|
|
|
|
|
|
|
|
|
# 输出文件 |
|
|
|
|
workerman # Linux 可执行文件 |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
### 运行方法 |
|
|
|
|
|
|
|
|
|
```bash |
|
|
|
|
# 直接运行 |
|
|
|
|
./workerman start |
|
|
|
|
|
|
|
|
|
# 后台运行 |
|
|
|
|
./workerman start -d |
|
|
|
|
|
|
|
|
|
# 查看状态 |
|
|
|
|
./workerman status |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
### 代码结构 |
|
|
|
|
|
|
|
|
|
**必须有 `main()` 函数** |
|
|
|
|
|
|
|
|
|
```php |
|
|
|
|
<?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() 函数签名 |
|
|
|
|
|
|
|
|
|
#### 方式一:无参数(默认) |
|
|
|
|
|
|
|
|
|
```php |
|
|
|
|
function main() { |
|
|
|
|
// 程序入口 |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
#### 方式二:带命令行参数 |
|
|
|
|
|
|
|
|
|
```php |
|
|
|
|
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 |
|
|
|
|
<?php |
|
|
|
|
namespace App\Controllers; |
|
|
|
|
|
|
|
|
|
class UserController { |
|
|
|
|
public function list() { |
|
|
|
|
return [ |
|
|
|
|
['id' => 1, 'name' => 'Alice'], |
|
|
|
|
['id' => 2, 'name' => 'Bob'], |
|
|
|
|
]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
**index.php**: |
|
|
|
|
```php |
|
|
|
|
<?php |
|
|
|
|
// 扩展模式:不需要 main() |
|
|
|
|
use App\Controllers\UserController; |
|
|
|
|
|
|
|
|
|
$controller = new UserController(); |
|
|
|
|
$data = $controller->list(); |
|
|
|
|
|
|
|
|
|
header('Content-Type: application/json'); |
|
|
|
|
echo json_encode($data); |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
**编译**: |
|
|
|
|
```bash |
|
|
|
|
php bin/compiler.php api-project/src/ --mode=ext -o api_extension |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
**使用**: |
|
|
|
|
```bash |
|
|
|
|
# 在 php-fpm 中作为扩展加载 |
|
|
|
|
# 通过 Web 服务器访问 |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
### 示例二:CLI 工具(二进制模式) |
|
|
|
|
|
|
|
|
|
**项目结构**: |
|
|
|
|
``` |
|
|
|
|
cli-tool/ |
|
|
|
|
├── src/ |
|
|
|
|
│ ├── Command.php |
|
|
|
|
│ └── main.php |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
**Command.php**: |
|
|
|
|
```php |
|
|
|
|
<?php |
|
|
|
|
class Command { |
|
|
|
|
public function execute($args) { |
|
|
|
|
echo "Executing with args: " . implode(' ', $args) . "\n"; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
**main.php**: |
|
|
|
|
```php |
|
|
|
|
<?php |
|
|
|
|
// 二进制模式:必须有 main() |
|
|
|
|
function main(int $argc, array $argv) { |
|
|
|
|
$command = new Command(); |
|
|
|
|
$command->execute(array_slice($argv, 1)); |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
**编译**: |
|
|
|
|
```bash |
|
|
|
|
php bin/compiler.php cli-tool/src/ -o mytool |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
**使用**: |
|
|
|
|
```bash |
|
|
|
|
./mytool arg1 arg2 arg3 |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
## 💡 最佳实践 |
|
|
|
|
|
|
|
|
|
### 扩展模式 |
|
|
|
|
|
|
|
|
|
1. **命名空间**: 使用唯一的命名空间避免冲突 |
|
|
|
|
```php |
|
|
|
|
namespace MyProject\Api; |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
2. **初始化**: 提供扩展初始化函数 |
|
|
|
|
```php |
|
|
|
|
function init_extension() { |
|
|
|
|
// 初始化逻辑 |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
3. **配置**: 支持通过 php.ini 配置 |
|
|
|
|
```php |
|
|
|
|
ini_set('my_extension.enabled', '1'); |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
### 二进制模式 |
|
|
|
|
|
|
|
|
|
1. **错误处理**: 在 main() 中处理全局异常 |
|
|
|
|
```php |
|
|
|
|
function main() { |
|
|
|
|
try { |
|
|
|
|
// 主逻辑 |
|
|
|
|
} catch (Throwable $e) { |
|
|
|
|
fwrite(STDERR, $e->getMessage()); |
|
|
|
|
exit(1); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
2. **信号处理**: 处理系统信号 |
|
|
|
|
```php |
|
|
|
|
function main() { |
|
|
|
|
pcntl_signal(SIGTERM, function() { |
|
|
|
|
echo "Shutting down...\n"; |
|
|
|
|
exit(0); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
// 主循环 |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
3. **日志记录**: 实现日志功能 |
|
|
|
|
```php |
|
|
|
|
function log_message($level, $message) { |
|
|
|
|
$timestamp = date('Y-m-d H:i:s'); |
|
|
|
|
echo "[{$timestamp}] [{$level}] {$message}\n"; |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
## 🔍 故障排除 |
|
|
|
|
|
|
|
|
|
### 扩展模式问题 |
|
|
|
|
|
|
|
|
|
#### 问题:扩展加载失败 |
|
|
|
|
|
|
|
|
|
```bash |
|
|
|
|
PHP Warning: PHP Startup: Unable to load dynamic library |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
**解决方案**: |
|
|
|
|
1. 检查文件权限:`chmod 644 coolify.so` |
|
|
|
|
2. 验证 PHP 版本匹配:`php -v` |
|
|
|
|
3. 检查依赖:`ldd coolify.so` |
|
|
|
|
|
|
|
|
|
#### 问题:Segmentation Fault |
|
|
|
|
|
|
|
|
|
**解决方案**: |
|
|
|
|
1. 检查代码中是否使用了不支持的语法 |
|
|
|
|
2. 查看错误日志:`tail -f /var/log/php/error.log` |
|
|
|
|
3. 使用 gdb 调试核心转储 |
|
|
|
|
|
|
|
|
|
### 二进制模式问题 |
|
|
|
|
|
|
|
|
|
#### 问题:Permission denied |
|
|
|
|
|
|
|
|
|
```bash |
|
|
|
|
bash: ./myapp: Permission denied |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
**解决方案**: |
|
|
|
|
```bash |
|
|
|
|
chmod +x myapp |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
#### 问题:找不到符号 |
|
|
|
|
|
|
|
|
|
```bash |
|
|
|
|
error while loading shared libraries |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
**解决方案**: |
|
|
|
|
```bash |
|
|
|
|
# 设置库路径 |
|
|
|
|
export LD_LIBRARY_PATH=/path/to/libs:$LD_LIBRARY_PATH |
|
|
|
|
|
|
|
|
|
# 或静态编译 |
|
|
|
|
php bin/compiler.php src/ -o app --static |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
## 📚 相关文档 |
|
|
|
|
|
|
|
|
|
- [快速入门指南](QUICKSTART.md) - 开始使用 AOT 编译器 |
|
|
|
|
- [语法支持规范](UNSUPPORTED_SYNTAX.md) - 了解支持的语法 |
|
|
|
|
- [性能优化指南](PERFORMANCE.md) - 提升编译和运行性能 |
|
|
|
|
- [故障排除](TROUBLESHOOTING.md) - 解决常见问题 |
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
**最后更新**: 2024 年 3 月 18 日 |
|
|
|
|
**文档版本**: v1.0 |