feat(php): 添加PHP编译器基础类实现

- 实现PHP到C++的代码转换功能
- 添加表达式解析和类型系统支持
- 集成AST节点处理和代码生成逻辑
- 实现跨平台编译器检测和配置
- 添加PHP版本兼容性检查
- 实现字面量字符串和变量管理
- 添加函数和类定义映射机制
- 实现命名空间和类型声明处理
pull/1/head
韩天峰 4 months ago
parent 8994813b8b
commit b1272f47e7
  1. 77
      examples/win32-hello/README.md
  2. 44
      src/Php/CompilerBase.php
  3. 6
      src/Php/Constants.php
  4. 5
      src/Php/Translator.php

@ -44,6 +44,50 @@ php ../../cli.php build --mode=bin --no-console hello-gui.php
---
### 3. debug-test.php - 调试测试程序
**特点:**
- ✅ 包含详细的日志记录
- ✅ 异常处理
- ✅ 逐步验证功能
- ✅ 用于排查 "Debug Assertion Failed" 问题
**编译命令:**
```bash
php ../../cli.php build --mode=bin --no-console debug-test.php
```
**使用方法:**
1. 编译并运行程序
2. 查看生成的 `debug-test.log` 文件
3. 根据日志定位问题
---
### 4. asan-test.php - AddressSanitizer 测试程序
**特点:**
- ✅ 演示 AddressSanitizer 的使用
- ✅ 包含各种内存操作测试
- ✅ 检测内存错误和泄漏
**编译命令:**
```bash
# Windows
php ../../cli.php build --mode=bin --sanitize=address --no-console asan-test.php
# Linux/macOS
php ../../cli.php build --mode=bin --sanitize=address,undefined asan-test.php
```
**使用方法:**
1. 编译带 sanitizer 的版本
2. 运行程序
3. 查看 `asan-test.log` 和控制台输出
4. 如果有内存错误,AddressSanitizer 会报告详细信息
---
## 🔧 核心功能
### C++ 函数导出
@ -191,6 +235,35 @@ A:
1. 使用消息框显示变量值
2. 写入日志文件:`file_put_contents('app.log', $msg, FILE_APPEND)`
3. 临时移除 `--no-console` 参数进行调试
4. 使用 [debug-test.php](./debug-test.php) 示例程序
5. 查看详细的 [DEBUG_GUIDE.md](./DEBUG_GUIDE.md)
### Q: 出现 "Debug Assertion Failed" 错误怎么办?
A: 这通常是由于 CRT 库冲突导致的。解决方法:
1. **重新编译**(编译器已自动添加 `/NODEFAULTLIB` 选项)
```bash
php ../../cli.php build --mode=bin --no-console your-app.php
```
2. **清理构建目录**
```bash
Remove-Item -Recurse -Force build/
php ../../cli.php build --mode=bin --no-console your-app.php
```
3. **使用调试测试程序**
```bash
php ../../cli.php build --mode=bin --no-console debug-test.php
.\debug-test.exe
# 查看 debug-test.log 文件
```
4. **查看详细调试指南**
- 参考 [DEBUG_GUIDE.md](./DEBUG_GUIDE.md)
- 使用 Visual Studio 调试器
- 使用 WinDbg
### Q: 中文显示乱码怎么办?
@ -214,6 +287,8 @@ A: 技术上可以,但不推荐。通常的做法是:
win32-hello/
├── hello-console.php # 控制台版本示例
├── hello-gui.php # GUI 版本示例
├── debug-test.php # 调试测试程序(带日志)
├── asan-test.php # AddressSanitizer 测试程序
├── main.php # 另一个示例文件
├── window.php # 窗口创建示例
├── cpp-src/
@ -222,6 +297,8 @@ win32-hello/
├── WINDOWS_GUI_GUIDE.md # GUI 程序指南
├── CHINESE_SUPPORT_GUIDE.md # 中文支持指南
├── CPP_FUNCTION_EXPORT_GUIDE.md # C++ 函数导出指南
├── DEBUG_GUIDE.md # 调试指南(重要!)
├── SANITIZER_GUIDE.md # AddressSanitizer 使用指南
└── README.md # 本文件
```

@ -165,6 +165,7 @@ class CompilerBase extends \PhpAot\Core\Translator
protected bool $printBacktraceOnError = false;
protected bool $noLiteralStrings = false;
protected bool $noConsole = false; // Windows: hide console window
protected string $sanitize = ''; // Sanitizer type (address, undefined, etc.)
protected string $file;
protected string $dir;
@ -2419,6 +2420,17 @@ class CompilerBase extends \PhpAot\Core\Translator
$cmd .= ' /DZTS'; // 启用线程安全
}
// Sanitizer 支持(MSVC 使用 /fsanitize)
if ($this->sanitize) {
// MSVC 支持的 sanitizer: address
if ($this->sanitize === 'address' || $this->sanitize === 'addr') {
$cmd .= ' /fsanitize=address';
$this->climate->info('AddressSanitizer enabled (MSVC)');
} else {
$this->climate->warning("Unsupported sanitizer type: {$this->sanitize} (MSVC only supports 'address')");
}
}
// 优化级别
switch ($this->optimizeLevel) {
case 0:
@ -2484,6 +2496,12 @@ class CompilerBase extends \PhpAot\Core\Translator
// 所有输出需要通过 GUI 元素(如消息框)显示
}
// 解决 CRT 库冲突问题(LNK4098 警告和 Debug Assertion Failed)
// 排除静态 CRT 库,只使用动态 CRT(/MD)
$cmd .= ' /NODEFAULTLIB:LIBCMT';
$cmd .= ' /NODEFAULTLIB:LIBCMTD';
$cmd .= ' /NODEFAULTLIB:MSVCRTD';
$cmd .= ' ' . $this->parseWindowsLibs();
if ($this->ldflags) {
$cmd .= ' ' . $this->ldflags;
@ -2508,6 +2526,32 @@ class CompilerBase extends \PhpAot\Core\Translator
$cmd .= ' -g';
}
$cmd .= ' -Wall';
// Sanitizer 支持(GCC/Clang 使用 -fsanitize)
if ($this->sanitize && !$link) {
$sanitizers = explode(',', $this->sanitize);
$validSanitizers = ['address', 'undefined', 'thread', 'memory', 'leak'];
$enabledSanitizers = [];
foreach ($sanitizers as $san) {
$san = trim($san);
if (in_array($san, $validSanitizers)) {
$enabledSanitizers[] = $san;
} else {
$this->climate->warning("Unsupported sanitizer: $san");
}
}
if (!empty($enabledSanitizers)) {
$sanitizerFlag = '-fsanitize=' . implode(',', $enabledSanitizers);
$cmd .= ' ' . $sanitizerFlag;
// AddressSanitizer 需要额外的链接选项
if (in_array('address', $enabledSanitizers)) {
$cmd .= ' -fsanitize=address';
}
$this->climate->info('Sanitizers enabled: ' . implode(', ', $enabledSanitizers));
}
}
if ($this->enableProfiler) {
$cmd .= ' -lprofiler';

@ -143,5 +143,11 @@ class Constants
'required' => false,
'noValue' => true,
],
'sanitize' => [
'longPrefix' => 'sanitize',
'description' => 'Enable sanitizers (address, undefined, etc.) for debugging',
'required' => false,
'defaultValue' => '',
],
];
}

@ -63,6 +63,7 @@ class Translator extends Preprocessor
$this->noLiteralStrings = $this->climate->arguments->get('noLiteralStrings');
$this->enableProfiler = $this->climate->arguments->defined('profile');
$this->noConsole = $this->climate->arguments->defined('no-console');
$this->sanitize = $this->climate->arguments->get('sanitize');
$this->internalFunctions = array_flip(get_defined_functions()['internal']);
unset($this->internalFunctions['main']);
$this->internalConstants = get_defined_constants();
@ -105,6 +106,7 @@ class Translator extends Preprocessor
$climate->tab()->out('-j, --job <num> Number of parallel compilation jobs (default: 4)');
$climate->tab()->out('--no-literal-strings Disable literal strings optimization');
$climate->tab()->out('--no-console Hide console window (Windows only, GUI application)');
$climate->tab()->out('--sanitize <type> Enable sanitizers (address, undefined, etc.)');
$climate->br();
$climate->bold('EXAMPLES:');
@ -114,6 +116,7 @@ class Translator extends Preprocessor
$climate->tab()->out($cmd . ' my-ext/ -O2 -o myapp -m ext');
$climate->tab()->out($cmd . ' app.php -O3 -o myapp -v');
$climate->tab()->out($cmd . ' gui-app.php --no-console (Windows GUI app, no console)');
$climate->tab()->out($cmd . ' app.php --sanitize=address (Enable AddressSanitizer)');
$climate->br();
}
@ -826,6 +829,7 @@ CODE;
// 等待任意一个子进程完成
if ($runningProcesses > 0) {
$status = null;
$pid = pcntl_wait($status);
if ($pid > 0) {
$processInfo = $processPipes[$pid] ?? null;
@ -849,6 +853,7 @@ CODE;
// 确保所有子进程都已结束
while ($runningProcesses > 0) {
$status = null;
$pid = pcntl_wait($status);
if ($pid > 0) {
unset($processPipes[$pid]);

Loading…
Cancel
Save