parent
67496f6bf6
commit
7ee5f8e018
7 changed files with 0 additions and 2511 deletions
@ -1,290 +0,0 @@ |
|||||||
# PHPX 编译器 - C++ 函数导出规范 |
|
||||||
|
|
||||||
## 概述 |
|
||||||
|
|
||||||
在 PHPX 编译器中,C++ 函数可以被导出为 PHP 函数,供 PHP 代码调用。这需要遵循特定的规范和约定。 |
|
||||||
|
|
||||||
## 三大必要条件 |
|
||||||
|
|
||||||
### 1. 函数名必须以 `php_` 为前缀 |
|
||||||
|
|
||||||
```cpp |
|
||||||
// ✅ 正确:以 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` | 无返回值 | 仅用于返回值 | |
|
||||||
|
|
||||||
```cpp |
|
||||||
// ✅ 正确:使用 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 |
|
||||||
<?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 |
|
||||||
<?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`) |
|
||||||
|
|
||||||
```cpp |
|
||||||
#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 |
|
||||||
<?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`) |
|
||||||
|
|
||||||
```yaml |
|
||||||
name: my-extension |
|
||||||
version: 0.0.1 |
|
||||||
sources: |
|
||||||
- main.php |
|
||||||
- ./cpp-src |
|
||||||
``` |
|
||||||
|
|
||||||
## 编译流程 |
|
||||||
|
|
||||||
``` |
|
||||||
1. 编译器读取 .stub.php 文件 |
|
||||||
↓ |
|
||||||
2. 生成对应的函数声明头文件 |
|
||||||
↓ |
|
||||||
3. 编译 C++ 实现文件(.cc/.cpp) |
|
||||||
↓ |
|
||||||
4. 链接所有目标文件 |
|
||||||
↓ |
|
||||||
5. 生成可执行文件或扩展 |
|
||||||
``` |
|
||||||
|
|
||||||
## 常见错误 |
|
||||||
|
|
||||||
### 错误 1:函数名没有 `php_` 前缀 |
|
||||||
|
|
||||||
```cpp |
|
||||||
// ❌ 错误 |
|
||||||
Int add(Int a, Int b) { |
|
||||||
return a + b; |
|
||||||
} |
|
||||||
|
|
||||||
// ✅ 正确 |
|
||||||
Int php_add(Int a, Int b) { |
|
||||||
return a + b; |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
**症状:** PHP 调用时提示函数未定义 |
|
||||||
|
|
||||||
### 错误 2:使用了原生 C/C++ 类型 |
|
||||||
|
|
||||||
```cpp |
|
||||||
// ❌ 错误 |
|
||||||
int php_add(int a, int b) { |
|
||||||
return a + b; |
|
||||||
} |
|
||||||
|
|
||||||
// ✅ 正确 |
|
||||||
Int php_add(Int a, Int b) { |
|
||||||
return a + b; |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
**症状:** 编译错误或类型不匹配 |
|
||||||
|
|
||||||
### 错误 3:没有在 stub 文件中声明 |
|
||||||
|
|
||||||
```cpp |
|
||||||
// C++ 中有实现 |
|
||||||
Int php_my_function(Int x) { |
|
||||||
return x * 2; |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
但没有在 `.stub.php` 中声明。 |
|
||||||
|
|
||||||
**症状:** PHP 调用时提示函数未定义 |
|
||||||
|
|
||||||
### 错误 4:Stub 和 C++ 实现类型不一致 |
|
||||||
|
|
||||||
```php |
|
||||||
// stub.php |
|
||||||
function add(int $a, int $b): string {} // 返回 string |
|
||||||
``` |
|
||||||
|
|
||||||
```cpp |
|
||||||
// mylib.cc |
|
||||||
Int php_add(Int a, Int b) { // 返回 Int,不一致! |
|
||||||
return a + b; |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
**症状:** 编译错误或运行时类型错误 |
|
||||||
|
|
||||||
## 最佳实践 |
|
||||||
|
|
||||||
1. **组织文件结构** |
|
||||||
- 将相关的 stub 和 C++ 文件放在同一目录 |
|
||||||
- 使用有意义的文件名(如 `winapi.stub.php` 和 `winapi.cc`) |
|
||||||
|
|
||||||
2. **类型安全** |
|
||||||
- 始终使用正确的 PHPX 类型 |
|
||||||
- 避免类型转换,除非必要 |
|
||||||
|
|
||||||
3. **注释清晰** |
|
||||||
- 在 stub 文件中添加函数说明 |
|
||||||
- 在 C++ 实现中添加详细注释 |
|
||||||
|
|
||||||
4. **错误处理** |
|
||||||
- 在 C++ 函数中进行参数验证 |
|
||||||
- 使用 `zend_throw_error()` 抛出异常 |
|
||||||
|
|
||||||
5. **命名规范** |
|
||||||
- 使用小写字母和下划线分隔单词 |
|
||||||
- 保持函数名简洁明了 |
|
||||||
|
|
||||||
## 参考资源 |
|
||||||
|
|
||||||
- [PHPX 官方文档](https://github.com/swoole/phpx) |
|
||||||
- [examples/prime](../prime) - 完整的 C++ 混合编程示例 |
|
||||||
- [examples/win32-hello](../win32-hello) - Windows API 封装示例 |
|
||||||
@ -1,112 +0,0 @@ |
|||||||
# Encoding Guide for PHPX Compiler |
|
||||||
|
|
||||||
## Problem |
|
||||||
|
|
||||||
When using Chinese characters in source code, you may encounter garbled text (乱码) like: |
|
||||||
``` |
|
||||||
Win32 Hello World 绋嬪簭 |
|
||||||
鏄剧ず娑堟伅妗?.. |
|
||||||
``` |
|
||||||
|
|
||||||
This happens because: |
|
||||||
1. Windows console uses code page 936 (GBK) by default |
|
||||||
2. Source files are saved as UTF-8 |
|
||||||
3. The mismatch causes encoding issues |
|
||||||
|
|
||||||
## Solution |
|
||||||
|
|
||||||
### Option 1: Use English (Recommended) ✅ |
|
||||||
|
|
||||||
All example files now use English to avoid encoding issues: |
|
||||||
|
|
||||||
**Before:** |
|
||||||
```php |
|
||||||
echo "显示消息框...\n"; |
|
||||||
``` |
|
||||||
|
|
||||||
**After:** |
|
||||||
```php |
|
||||||
echo "Showing message box...\n"; |
|
||||||
``` |
|
||||||
|
|
||||||
### Option 2: Set Console to UTF-8 |
|
||||||
|
|
||||||
If you must use Chinese, set the console code page to UTF-8 before running: |
|
||||||
|
|
||||||
```powershell |
|
||||||
chcp 65001 |
|
||||||
.\win32_hello.exe |
|
||||||
``` |
|
||||||
|
|
||||||
Or in your PHP code, set it programmatically: |
|
||||||
|
|
||||||
```php |
|
||||||
function main() { |
|
||||||
// Set console to UTF-8 |
|
||||||
exec('chcp 65001 > nul'); |
|
||||||
|
|
||||||
echo "显示消息框...\n"; |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
### Option 3: Use Windows API for Unicode |
|
||||||
|
|
||||||
For message boxes and Windows GUI, use wide character functions: |
|
||||||
|
|
||||||
```cpp |
|
||||||
// In C++ file |
|
||||||
Int php_messagebox(Int hWnd, String text, String caption, Int uType) { |
|
||||||
// Convert UTF-8 to UTF-16 for Windows API |
|
||||||
int wtext_len = MultiByteToWideChar(CP_UTF8, 0, text.data(), -1, NULL, 0); |
|
||||||
wchar_t* wtext = new wchar_t[wtext_len]; |
|
||||||
MultiByteToWideChar(CP_UTF8, 0, text.data(), -1, wtext, wtext_len); |
|
||||||
|
|
||||||
int wcaption_len = MultiByteToWideChar(CP_UTF8, 0, caption.data(), -1, NULL, 0); |
|
||||||
wchar_t* wcaption = new wchar_t[wcaption_len]; |
|
||||||
MultiByteToWideChar(CP_UTF8, 0, caption.data(), -1, wcaption, wcaption_len); |
|
||||||
|
|
||||||
int result = MessageBoxW((HWND)hWnd, wtext, wcaption, (UINT)uType); |
|
||||||
|
|
||||||
delete[] wtext; |
|
||||||
delete[] wcaption; |
|
||||||
return result; |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
## Best Practices |
|
||||||
|
|
||||||
1. **Use English for code comments and strings** - Most portable solution |
|
||||||
2. **Save all files as UTF-8 without BOM** - Standard for modern development |
|
||||||
3. **Avoid mixing encodings** - Keep consistency across all files |
|
||||||
4. **Test on target systems** - Different Windows versions may have different defaults |
|
||||||
|
|
||||||
## Current Status |
|
||||||
|
|
||||||
All files in `examples/win32-hello/` now use English: |
|
||||||
- ✅ hello-win.php |
|
||||||
- ✅ main.php |
|
||||||
- ✅ window.php |
|
||||||
- ✅ cpp-src/winapi.cc |
|
||||||
- ✅ cpp-src/winapi.stub.php |
|
||||||
|
|
||||||
Rebuild to see the changes: |
|
||||||
|
|
||||||
```powershell |
|
||||||
php bin\compiler.php examples\win32-hello\project.yml |
|
||||||
.\build\win32_hello.exe |
|
||||||
``` |
|
||||||
|
|
||||||
Expected output: |
|
||||||
``` |
|
||||||
======================================== |
|
||||||
Win32 Hello World Program |
|
||||||
======================================== |
|
||||||
|
|
||||||
Showing message box... |
|
||||||
Message box return value: 1 |
|
||||||
|
|
||||||
Note: To create a full window, you need to implement window procedure and message loop. |
|
||||||
This requires WNDCLASS registration and message pump in C++ layer. |
|
||||||
|
|
||||||
Program ended. Press any key to exit... |
|
||||||
``` |
|
||||||
Loading…
Reference in new issue