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.
5.8 KiB
5.8 KiB
PHPX 编译器 - C++ 函数导出规范
概述
在 PHPX 编译器中,C++ 函数可以被导出为 PHP 函数,供 PHP 代码调用。这需要遵循特定的规范和约定。
三大必要条件
1. 函数名必须以 php_ 为前缀
// ✅ 正确:以 php_ 为前缀
Int php_messagebox(Int hWnd, String text, String caption, Int uType) {
// 实现代码
}
// ❌ 错误:缺少 php_ 前缀
Int messagebox(Int hWnd, String text, String caption, Int uType) {
// 这不会被导出到 PHP
}
命名规则:
- C++ 函数名:
php_messagebox() - PHP 调用名:
messagebox()(自动去掉php_前缀)
2. 只能使用 PHPX 类型作为参数和返回值
支持的 PHPX 类型:
| PHPX 类型 | PHP 对应类型 | 说明 |
|---|---|---|
Int |
int |
整数 |
Bool |
bool |
布尔值 |
Double |
float |
浮点数 |
String |
string |
字符串 |
Array |
array |
数组 |
Object |
object |
对象 |
Variant |
mixed |
混合类型 |
void |
无返回值 | 仅用于返回值 |
// ✅ 正确:使用 PHPX 类型
Int php_add(Int a, Int b) {
return a + b;
}
String php_greet(String name) {
return "Hello, " + name + "!";
}
// ❌ 错误:使用原生 C/C++ 类型
int php_add(int a, int b) { // 错误!
return a + b;
}
char* php_greet(char* name) { // 错误!
return name;
}
3. 必须在 .stub.php 文件中声明
Stub 文件的作用:
- 只包含函数签名(参数和返回值类型)
- 不包含具体实现代码
- 让编译器知道有哪些 C++ 函数可供 PHP 调用
Stub 文件示例 (winapi.stub.php):
<?php
/**
* Windows API 封装函数的声明文件(stub)
* 这些函数在 C++ 中实现,PHP 层只负责声明
*/
// 显示消息框
function messagebox(int $hWnd, string $text, string $caption, int $uType): int {}
// 获取模块句柄
function get_module_handle(string $moduleName): int {}
// 创建窗口
function create_window(
string $className,
string $windowName,
int $style,
int $x,
int $y,
int $width,
int $height
): int {}
// 显示窗口
function show_window(int $hWnd, int $cmdShow): bool {}
// 退出消息循环
function post_quit_message(int $exitCode): void {}
注意事项:
- Stub 文件必须是
.stub.php扩展名 - 函数体为空(
{}),不包含任何代码 - 参数类型和返回值类型必须与 C++ 实现一致
- 函数名不需要
php_前缀(编译器会自动添加)
完整示例
项目结构
my-extension/
├── main.php # PHP 主程序
├── cpp-src/
│ ├── mylib.stub.php # Stub 声明文件
│ └── mylib.cc # C++ 实现文件
└── project.yml # 项目配置
1. Stub 声明文件 (cpp-src/mylib.stub.php)
<?php
// 计算两个整数的和
function add(int $a, int $b): int {}
// 拼接字符串
function concat(string $str1, string $str2): string {}
// 判断是否为偶数
function is_even(int $number): bool {}
2. C++ 实现文件 (cpp-src/mylib.cc)
#include <phpx.h>
using namespace php;
// 注意:函数名必须以 php_ 为前缀
Int php_add(Int a, Int b) {
return a + b;
}
String php_concat(String str1, String str2) {
return str1 + str2;
}
Bool php_is_even(Int number) {
return (number % 2 == 0);
}
3. PHP 调用文件 (main.php)
<?php
function main() {
// 直接调用 C++ 函数,无需额外声明
$sum = add(10, 20);
echo "10 + 20 = $sum\n"; // 输出: 10 + 20 = 30
$greeting = concat("Hello, ", "World!");
echo "$greeting\n"; // 输出: Hello, World!
if (is_even(42)) {
echo "42 是偶数\n";
}
}
4. 项目配置 (project.yml)
name: my-extension
version: 0.0.1
sources:
- main.php
- ./cpp-src
编译流程
1. 编译器读取 .stub.php 文件
↓
2. 生成对应的函数声明头文件
↓
3. 编译 C++ 实现文件(.cc/.cpp)
↓
4. 链接所有目标文件
↓
5. 生成可执行文件或扩展
常见错误
错误 1:函数名没有 php_ 前缀
// ❌ 错误
Int add(Int a, Int b) {
return a + b;
}
// ✅ 正确
Int php_add(Int a, Int b) {
return a + b;
}
症状: PHP 调用时提示函数未定义
错误 2:使用了原生 C/C++ 类型
// ❌ 错误
int php_add(int a, int b) {
return a + b;
}
// ✅ 正确
Int php_add(Int a, Int b) {
return a + b;
}
症状: 编译错误或类型不匹配
错误 3:没有在 stub 文件中声明
// C++ 中有实现
Int php_my_function(Int x) {
return x * 2;
}
但没有在 .stub.php 中声明。
症状: PHP 调用时提示函数未定义
错误 4:Stub 和 C++ 实现类型不一致
// stub.php
function add(int $a, int $b): string {} // 返回 string
// mylib.cc
Int php_add(Int a, Int b) { // 返回 Int,不一致!
return a + b;
}
症状: 编译错误或运行时类型错误
最佳实践
-
组织文件结构
- 将相关的 stub 和 C++ 文件放在同一目录
- 使用有意义的文件名(如
winapi.stub.php和winapi.cc)
-
类型安全
- 始终使用正确的 PHPX 类型
- 避免类型转换,除非必要
-
注释清晰
- 在 stub 文件中添加函数说明
- 在 C++ 实现中添加详细注释
-
错误处理
- 在 C++ 函数中进行参数验证
- 使用
zend_throw_error()抛出异常
-
命名规范
- 使用小写字母和下划线分隔单词
- 保持函数名简洁明了
参考资源
- PHPX 官方文档
- examples/prime - 完整的 C++ 混合编程示例
- examples/win32-hello - Windows API 封装示例