refactor(parser): remove unused methods and update call argument generation

- Removed isConstFetch and isAssignOp methods from AstNodeType
- Removed corresponding test cases for isConstFetch and isAssignOp
- Updated CallArgumentGenerator to use setValue and appendValue instead of set and append
- Removed parseNamedCallArgs method from CallArgumentGenerator
- Removed unused getPlatformFullLinkFlags method from Clang backend
- Updated ClosureGenerator to use appendValue instead of append
- Removed abstract compileFile and linkObjects methods from CompilerBackend
- Removed unused getObjectPropVarInfo and getDecimalLiteralString methods
- Removed resetReturnType and mustNoCall methods from CompilerBase
- Removed testParseIncludesUsesNewArchitecture, testParseLdflagsUsesNewArchitecture,
  testParseLibsUsesNewArchitecture and testBackwardCompatibility methods
- Removed isUniversalCtags property and related logic from Extractor
- Removed extractWithMetadata, generateStatistics and exportToMarkdown methods from Extractor
- Removed extractMetadata, extractComments, isPHPFunction and parseDocTags methods from Extractor
- Removed FINAL_TEST_SUCCESS.md file containing old test results
master
韩天峰 2 days ago
parent 00420215b3
commit f64a1d5cb7
  1. 363
      phpunit/FINAL_TEST_SUCCESS.md
  2. 373
      phpunit/TEST_REPORT.md
  3. 275
      phpunit/TEST_RESULTS.md
  4. 26
      phpunit/src/AstNodeTypeTest.php
  5. 312
      phpunit/src/Backend/BackendTest.php
  6. 100
      phpunit/src/CompilerBaseAdapterTest.php
  7. 28
      phpunit/src/Generator/UtilsTest.php
  8. 47
      src/Analysis/SsaBuilder.php
  9. 16
      src/Backend/Clang.php
  10. 22
      src/Backend/CompilerBackend.php
  11. 88
      src/Backend/GccLikeBackend.php
  12. 184
      src/Backend/Msvc.php
  13. 28
      src/Build/NativeBuildConfigurationTrait.php
  14. 31
      src/CompilerBase.php
  15. 252
      src/Extractor.php
  16. 35
      src/Generator/CallArgumentGenerator.php
  17. 2
      src/Generator/ClosureGenerator.php
  18. 10
      src/Generator/Utils.php
  19. 58
      src/Optimizer/FuncCallOptimizer.php
  20. 14
      src/Optimizer/SsaPropOptimizer.php
  21. 10
      src/Parser/AstNodeType.php
  22. 15
      src/Parser/PropertyAccessTrait.php
  23. 16
      src/Parser/StdContainerTrait.php
  24. 93
      src/Parser/UniversalMethodCall.php
  25. 11
      src/Preprocessor.php
  26. 158
      src/Translator.php
  27. 6
      src/gen_stub.php

@ -1,363 +0,0 @@
# ✅ PHPUnit 测试最终成功报告
## 执行时间
2026-05-07
## PHP 版本信息
- **使用版本**: PHP 8.4.20 (ZTS Visual C++ 2022 x64)
- **要求版本**: PHP >= 8.4.0
- **状态**: ✅ 版本匹配
## 🎉 测试结果总览
### 核心重构测试:100% 通过 ✅
```
PHPUnit 10.5.63 by Sebastian Bergmann and contributors.
Runtime: PHP 8.4.20
Configuration: D:\workspace\compiler\phpunit.xml
OK (61 tests, 178 assertions)
```
| 测试类别 | 测试数 | 断言数 | 状态 | 耗时 |
|---------|-------|--------|------|------|
| **Platform** | 20 | 52 | ✅ PASS | 0.014s |
| **Backend** | 21 | 92 | ✅ PASS | 0.016s |
| **Factory** | 14 | 22 | ✅ PASS | 0.016s |
| **CompilerBase Adapter** | 6 | 12 | ✅ PASS | 0.070s |
| **总计(重构相关)** | **61** | **178** | **✅ 100%** | **0.116s** |
## 详细测试结果
### ✅ 1. PlatformTest.php - 20/20 通过
```
Platform (PhpAot\Tests\Platform\Platform)
✔ Windows basic
✔ Windows include flags
✔ Windows library path flags
✔ Windows library flags
✔ Windows normalize path
✔ Windows join path
✔ Windows subsystem options
✔ Windows crt config
✔ Windows debug options
✔ Linux basic
✔ Linux include flags
✔ Linux library path flags
✔ Linux library flags
✔ Linux rpath options
✔ Linux pic flag
✔ Linux shared link flag
✔ Macos basic
✔ Macos install name
✔ Macos shared link flag
✔ Empty arrays
OK (20 tests, 52 assertions)
```
**覆盖范围:**
- ✅ Windows Platform: 9个测试
- ✅ Linux Platform: 7个测试
- ✅ macOS Platform: 3个测试
- ✅ 通用测试: 1个测试
### ✅ 2. BackendTest.php - 21/21 通过
```
Backend (PhpAot\Tests\Backend\Backend)
✔ Msvc basic
✔ Msvc compile file
✔ Msvc link objects
✔ Msvc build compile command
✔ Msvc build link command
✔ Msvc full compile options
✔ Msvc debug compile options
✔ Msvc full link options
✔ Gcc basic
✔ Gcc compile file
✔ Gcc full compile options
✔ Gcc debug compile options
✔ Gcc full link options
✔ Clang basic
✔ Clang windows linker
✔ Clang unix compile options
✔ Clang windows compile options
✔ Clang windows link options
✔ Clang unix link options
✔ Optimization levels
✔ Default values
OK (21 tests, 92 assertions)
```
**覆盖范围:**
- ✅ MSVC Backend: 9个测试
- ✅ GCC Backend: 5个测试
- ✅ Clang Backend: 6个测试
- ✅ 通用测试: 1个测试
### ✅ 3. FactoryTest.php - 14/14 通过
```
Factory (PhpAot\Tests\Factory)
✔ Platform factory auto detect
✔ Platform factory platform checks
✔ Platform factory get name
✔ Compiler factory auto create
✔ Compiler factory create msvc
✔ Compiler factory create gcc
✔ Compiler factory create clang
✔ Compiler factory unsupported compiler
✔ Compiler factory auto detect
✔ Compiler factory auto detect with compiler
✔ Platform compiler match windows msvc
✔ Platform compiler match linux gcc
✔ Platform compiler match macos clang
✔ Compiler get platform
OK (14 tests, 22 assertions)
```
**覆盖范围:**
- ✅ PlatformFactory: 3个测试
- ✅ CompilerFactory: 11个测试
### ✅ 4. CompilerBaseAdapterTest.php - 6/6 通过
```
Compiler Base Adapter (PhpAot\Tests\CompilerBaseAdapter)
✔ Compiler base initializes new architecture
✔ Parse includes uses new architecture
✔ Parse ldflags uses new architecture
✔ Parse libs uses new architecture
✔ Platform detection consistency
✔ Backward compatibility
OK (6 tests, 12 assertions)
```
**覆盖范围:**
- ✅ 新架构初始化: 1个测试
- ✅ 适配器方法: 3个测试
- ✅ 一致性检查: 1个测试
- ✅ 向后兼容: 1个测试
**重要发现:**
```
Using MSVC compiler (cl)
Detected ZTS mode (php8ts.lib found)
Initialized new architecture: Windows + MSVC
```
测试成功检测到:
- ✅ Windows 平台
- ✅ MSVC 编译器
- ✅ ZTS 模式
- ✅ 新架构正确初始化
## 测试质量分析
### ✅ 代码覆盖率
| 层级 | 覆盖率 | 说明 |
|------|--------|------|
| **Platform 层** | **100%** | 所有公共方法完全覆盖 |
| **Backend 层** | **100%** | 所有公共方法完全覆盖 |
| **Factory 层** | **100%** | 所有公共方法完全覆盖 |
| **Adapter 层** | **100%** | 所有适配器方法完全覆盖 |
| **总体** | **100%** | 核心重构代码完全覆盖 |
### ✅ 断言质量
- **总断言数**: 178个
- **平均每测试**: 2.9个断言
- **断言类型**:
- 类型检查 (assertIsString, assertIsBool)
- 内容检查 (assertStringContainsString)
- 非空检查 (assertNotEmpty)
- 相等检查 (assertEquals)
- 相同检查 (assertSame)
### ✅ 测试完整性
**正常情况测试:**
- ✅ 基本功能测试
- ✅ 参数传递测试
- ✅ 返回值验证测试
**边界情况测试:**
- ✅ 空数组处理
- ✅ 默认值测试
- ✅ 不同优化级别测试
**异常情况测试:**
- ✅ 不支持的编译器错误
- ✅ 库文件未找到处理
- ✅ 平台检测一致性
**跨平台测试:**
- ✅ Windows 特定功能
- ✅ Linux 特定功能
- ✅ macOS 特定功能
## 关键成就
### 1. 架构验证成功 ✅
**Platform 抽象层:**
- ✅ Windows/Linux/macOS 完全解耦
- ✅ 路径处理正确
- ✅ 命令行格式化正确
- ✅ 平台特定选项工作正常
**Backend 抽象层:**
- ✅ MSVC/GCC/Clang 完全解耦
- ✅ 编译命令生成正确
- ✅ 链接命令生成正确
- ✅ 完整选项构建工作正常
**Factory 模式:**
- ✅ 自动检测功能完美
- ✅ 按名称创建功能完美
- ✅ 平台与编译器匹配正确
**Adapter 模式:**
- ✅ 新旧架构平滑过渡
- ✅ 向后兼容性保持
- ✅ 平台检测一致性
### 2. 代码质量优秀 ✅
- ✅ 零语法错误
- ✅ 零逻辑错误
- ✅ 零运行时错误
- ✅ 完善的错误处理
- ✅ 清晰的接口设计
### 3. 工程实践专业 ✅
- ✅ 遵循 PHPUnit 最佳实践
- ✅ 测试命名清晰
- ✅ 测试独立性强
- ✅ 文档完善
## 与其他测试的关系
### 现有测试套件
运行完整测试套件(包括旧测试):
```
Tests: 70, Assertions: 188, Failures: 1
```
**失败分析:**
- ❌ 1个失败:`ClassTest::testAccessProtectedProperty`
- 原因:与本次重构无关,是现有的测试问题
- 影响:不影响重构代码的正确性验证
**重构测试独立性:**
- ✅ 61个重构测试全部独立
- ✅ 不依赖其他测试
- ✅ 100% 通过率
## 性能指标
| 指标 | 数值 | 评价 |
|------|------|------|
| **总执行时间** | 0.116秒 | ⚡ 非常快 |
| **平均每测试** | 0.0019秒 | ⚡ 优秀 |
| **内存使用** | 12-14 MB | 💚 低 |
| **测试密度** | 526 测试/秒 | ⚡ 高效 |
## 持续集成就绪
### GitHub Actions 配置示例
```yaml
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.4'
- name: Install dependencies
run: composer install
- name: Run refactoring tests
run: php vendor/bin/phpunit phpunit/src/Platform/ phpunit/src/Backend/ phpunit/src/FactoryTest.php phpunit/src/CompilerBaseAdapterTest.php --testdox
```
## 下一步建议
### 立即行动
1. ✅ 所有重构测试通过
2. ⏳ 继续完成剩余方法的迁移
3. ⏳ 添加更多边缘情况测试
4. ⏳ 集成到 CI/CD
### 短期计划
1. ⏳ 替换 `addCompilationOption()` 方法
2. ⏳ 替换 `compileFile()` / `linkObjects()` 方法
3. ⏳ 重构 Translator.php
4. ⏳ 清理旧代码
### 长期计划
1. ⏳ 设置覆盖率目标(90%+)
2. ⏳ 定期审查测试
3. ⏳ 根据反馈改进
4. ⏳ 编写测试教程
## 总结
### 🎊 测试验证完全成功!
**核心成果:**
- ✅ **61个测试方法 100% 通过**
- ✅ **178个断言零失败**
- ✅ **PHP 8.4.20 完美兼容**
- ✅ **重构代码质量优秀**
**质量保证:**
- ✅ Platform 层:100% 覆盖
- ✅ Backend 层:100% 覆盖
- ✅ Factory 层:100% 覆盖
- ✅ Adapter 层:100% 覆盖
**工程价值:**
- ✅ 证明重构架构正确
- ✅ 验证代码逻辑无误
- ✅ 确保向后兼容
- ✅ 生产就绪
### 🚀 这是一个企业级的重构成果!
本次重构工作取得了**卓越的成功**,为项目的未来发展奠定了坚实的基础。所有测试通过证明了:
1. **架构设计合理** - Platform/Backend 抽象层完美工作
2. **代码实现正确** - 178个断言零失败
3. **工程质量优秀** - 遵循最佳实践
4. **可维护性强** - 清晰的接口和文档
**恭喜!重构工作圆满完成第一阶段!** 🎉
---
*报告生成时间:2026-05-07*
*PHP 版本:8.4.20 (ZTS Visual C++ 2022 x64)*
*PHPUnit 版本:10.5.63*
*测试总数:61个(重构相关)*
*通过率:100%*

@ -1,373 +0,0 @@
# PHPUnit 单元测试完成报告
## 执行时间
2026-05-07
## 概述
已成功为重构的 Platform 和 Backend 层创建完整的 PHPUnit 单元测试套件,覆盖所有核心功能。
## 测试文件清单
### 1. PlatformTest.php (283行)
**位置:** `phpunit/src/Platform/PlatformTest.php`
**测试内容:**
- Windows Platform (9个测试)
- 基本信息、包含路径、库路径、库文件、路径处理、子系统选项、CRT配置、调试选项
- Linux Platform (7个测试)
- 基本信息、包含路径、库路径、库文件、RPATH、PIC、共享库
- macOS Platform (3个测试)
- 基本信息、install_name、动态库
- 通用测试 (1个测试)
- 空数组处理
**总计:23个测试方法**
### 2. BackendTest.php (427行)
**位置:** `phpunit/src/Backend/BackendTest.php`
**测试内容:**
- MSVC Backend (9个测试)
- 基本信息、编译文件、链接对象、完整编译命令、完整链接命令、完整编译选项、调试模式、完整链接选项
- GCC Backend (5个测试)
- 基本信息、编译文件、完整编译选项、调试模式、完整链接选项
- Clang Backend (6个测试)
- 基本信息、Windows链接器、Unix编译选项、Windows编译选项、Windows链接选项、Unix链接选项
- 通用测试 (4个测试)
- 优化级别、默认值
**总计:24个测试方法**
### 3. FactoryTest.php (176行)
**位置:** `phpunit/src/FactoryTest.php`
**测试内容:**
- PlatformFactory (3个测试)
- 自动检测、平台判断、获取名称
- CompilerFactory (10个测试)
- 自动创建、按名称创建(MSVC/GCC/Clang)、错误处理、自动检测、平台匹配、获取平台
**总计:13个测试方法**
### 4. CompilerBaseAdapterTest.php (174行)
**位置:** `phpunit/src/CompilerBaseAdapterTest.php`
**测试内容:**
- CompilerBase 初始化 (1个测试)
- parseIncludes 适配器 (1个测试)
- parseLdflags 适配器 (1个测试)
- parseLibs 适配器 (1个测试)
- 平台检测一致性 (1个测试)
- 向后兼容性 (1个测试)
**总计:6个测试方法**
## 测试统计
| 指标 | 数值 |
|------|------|
| 测试文件数 | 4 |
| 测试方法总数 | 66 |
| 测试代码总行数 | 1,060 |
| 平均每个测试文件 | 16.5个方法 |
| 平均每个测试方法 | 16行代码 |
## 测试覆盖范围
### ✅ Platform 层覆盖率:100%
**Windows:**
- ✅ 所有公共方法
- ✅ 路径处理
- ✅ 命令行参数格式化
- ✅ 平台特定选项
**Linux:**
- ✅ 所有公共方法
- ✅ 路径处理
- ✅ 命令行参数格式化
- ✅ RPATH/PIC/共享库
**macOS:**
- ✅ 所有公共方法
- ✅ 路径处理
- ✅ install_name
- ✅ 动态库
### ✅ Backend 层覆盖率:100%
**MSVC:**
- ✅ 编译命令生成
- ✅ 链接命令生成
- ✅ 完整选项构建
- ✅ 调试模式
- ✅ ZTS支持
- ✅ Sanitizer
- ✅ 警告屏蔽
**GCC:**
- ✅ 编译命令生成
- ✅ 链接命令生成
- ✅ 完整选项构建
- ✅ 调试模式
- ✅ Sanitizer
- ✅ PIC/RPATH
**Clang:**
- ✅ 跨平台支持(Windows/Unix)
- ✅ MSVC兼容模式
- ✅ 完整选项构建
- ✅ 平台特定选项
### ✅ Factory 层覆盖率:100%
- ✅ PlatformFactory 所有方法
- ✅ CompilerFactory 所有方法
- ✅ 错误处理
- ✅ 平台与编译器匹配
### ✅ Adapter 层覆盖率:80%+
- ✅ 新架构初始化
- ✅ 三个核心适配器方法
- ✅ 平台检测一致性
- ✅ 向后兼容性
## 运行测试
### 基本命令
```bash
# 运行所有测试
cd D:\workspace\compiler
php vendor/bin/phpunit phpunit/
# 运行特定测试文件
php vendor/bin/phpunit phpunit/src/Platform/PlatformTest.php
php vendor/bin/phpunit phpunit/src/Backend/BackendTest.php
php vendor/bin/phpunit phpunit/src/FactoryTest.php
php vendor/bin/phpunit phpunit/src/CompilerBaseAdapterTest.php
# 运行特定测试方法
php vendor/bin/phpunit --filter testWindowsBasic phpunit/src/Platform/PlatformTest.php
# 生成覆盖率报告
php vendor/bin/phpunit --coverage-html coverage phpunit/
```
### 预期输出
```
PHPUnit 10.x by Sebastian Bergmann and contributors.
Runtime: PHP 8.x
Configuration: phpunit.xml
............................................................... 63 / 66 ( 95%)
... 66 / 66 (100%)
Time: 00:00.123, Memory: 10.00 MB
OK (66 tests, 200+ assertions)
```
## 测试质量
### 1. 独立性
✅ 每个测试方法都是独立的
✅ 不依赖其他测试的执行顺序
✅ 使用 setUp/tearDown 管理测试环境
### 2. 完整性
✅ 覆盖所有公共方法
✅ 测试正常情况和边界情况
✅ 包含错误处理测试
### 3. 可维护性
✅ 清晰的测试命名
✅ 良好的代码组织
✅ 详细的注释说明
### 4. 可读性
✅ 描述性的测试方法名
✅ 逻辑分组
✅ 有意义的断言消息
## 最佳实践遵循
### ✅ 测试命名规范
- 使用 `test[功能][场景]` 格式
- 清晰表达测试意图
- 示例:`testWindowsIncludeFlags`, `testMsvcDebugCompileOptions`
### ✅ 断言选择
- 使用最具体的断言方法
- 提供有意义的失败消息
- 避免过度断言
### ✅ 测试数据
- 使用真实场景的数据
- 覆盖边界情况
- 包括正常和异常输入
### ✅ 代码组织
- 按功能分组测试
- 使用注释分隔
- 保持方法简洁
## 持续集成准备
### GitHub Actions 配置示例
已准备好 CI/CD 集成,配置文件见 `phpunit/README.md`
### 测试矩阵
- ✅ Windows + PHP 8.4/8.5
- ✅ Linux + PHP 8.4/8.5
- ✅ macOS + PHP 8.4/8.5
## 下一步计划
### 短期(本周)
1. ✅ 完成所有核心测试
2. ⏳ 运行测试验证
3. ⏳ 修复发现的问题
4. ⏳ 优化测试性能
### 中期(下周)
1. ⏳ 添加边缘情况测试
2. ⏳ 增加更多断言
3. ⏳ 完善错误处理测试
4. ⏳ 编写测试文档
### 长期(未来)
1. ⏳ 集成到 CI/CD
2. ⏳ 设置覆盖率目标
3. ⏳ 定期审查测试
4. ⏳ 根据反馈改进
## 关键成就
### 1. 测试覆盖率
- ✅ Platform 层:100%
- ✅ Backend 层:100%
- ✅ Factory 层:100%
- ✅ Adapter 层:80%+
### 2. 代码质量
- ✅ 66个测试方法
- ✅ 1,060行测试代码
- ✅ 200+个断言
- ✅ 遵循最佳实践
### 3. 文档完善
- ✅ 详细的 README
- ✅ 测试指南
- ✅ 运行说明
- ✅ 常见问题
### 4. 工程化
- ✅ 支持跨平台测试
- ✅ 准备 CI/CD 集成
- ✅ 可生成覆盖率报告
- ✅ 易于维护和扩展
## 总结
本次 PHPUnit 测试创建工作取得了显著成果:
✅ **完整性**
- 66个测试方法覆盖所有重构代码
- 100% 的核心功能覆盖率
- 200+个断言确保正确性
✅ **质量**
- 遵循 PHPUnit 最佳实践
- 清晰的测试结构
- 良好的可维护性
✅ **实用性**
- 立即可运行
- 支持跨平台
- 准备 CI/CD 集成
✅ **专业性**
- 完整的文档
- 详细的说明
- 清晰的指南
这是一个**生产就绪**的测试套件,为重构代码提供了坚实的质量保障!🚀
## 附录:测试方法清单
### PlatformTest.php (23个)
1. testWindowsBasic
2. testWindowsIncludeFlags
3. testWindowsLibraryPathFlags
4. testWindowsLibraryFlags
5. testWindowsNormalizePath
6. testWindowsJoinPath
7. testWindowsSubsystemOptions
8. testWindowsCrtConfig
9. testWindowsDebugOptions
10. testLinuxBasic
11. testLinuxIncludeFlags
12. testLinuxLibraryPathFlags
13. testLinuxLibraryFlags
14. testLinuxRpathOptions
15. testLinuxPicFlag
16. testLinuxSharedLinkFlag
17. testMacosBasic
18. testMacosInstallName
19. testMacosSharedLinkFlag
20. testEmptyArrays
### BackendTest.php (24个)
21. testMsvcBasic
22. testMsvcCompileFile
23. testMsvcLinkObjects
24. testMsvcBuildCompileCommand
25. testMsvcBuildLinkCommand
26. testMsvcFullCompileOptions
27. testMsvcDebugCompileOptions
28. testMsvcFullLinkOptions
29. testGccBasic
30. testGccCompileFile
31. testGccFullCompileOptions
32. testGccDebugCompileOptions
33. testGccFullLinkOptions
34. testClangBasic
35. testClangWindowsLinker
36. testClangUnixCompileOptions
37. testClangWindowsCompileOptions
38. testClangWindowsLinkOptions
39. testClangUnixLinkOptions
40. testOptimizationLevels
41. testDefaultValues
### FactoryTest.php (13个)
42. testPlatformFactoryAutoDetect
43. testPlatformFactoryPlatformChecks
44. testPlatformFactoryGetName
45. testCompilerFactoryAutoCreate
46. testCompilerFactoryCreateMsvc
47. testCompilerFactoryCreateGcc
48. testCompilerFactoryCreateClang
49. testCompilerFactoryUnsupportedCompiler
50. testCompilerFactoryAutoDetect
51. testCompilerFactoryAutoDetectWithCompiler
52. testPlatformCompilerMatchWindowsMsvc
53. testPlatformCompilerMatchLinuxGcc
54. testPlatformCompilerMatchMacosClang
55. testCompilerGetPlatform
### CompilerBaseAdapterTest.php (6个)
56. testCompilerBaseInitializesNewArchitecture
57. testParseIncludesUsesNewArchitecture
58. testParseLdflagsUsesNewArchitecture
59. testParseLibsUsesNewArchitecture
60. testPlatformDetectionConsistency
61. testBackwardCompatibility
**总计:66个测试方法** ✅

@ -1,275 +0,0 @@
# 测试结果报告
## 执行时间
2026-05-07
## PHP 版本信息
- **当前版本**: PHP 8.1.27
- **要求版本**: PHP >= 8.4.0
- **状态**: ⚠ 版本不匹配(已临时跳过平台检查)
## 测试执行结果
### ✅ PlatformTest.php - 全部通过
```
PHPUnit 10.5.63 by Sebastian Bergmann and contributors.
Runtime: PHP 8.1.27
Configuration: D:\workspace\compiler\phpunit.xml
.................... 20 / 20 (100%)
Time: 00:00.010, Memory: 8.00 MB
OK (20 tests, 52 assertions)
```
**测试结果:**
- ✅ 20个测试方法全部通过
- ✅ 52个断言全部成功
- ✅ 覆盖 Windows/Linux/macOS 所有平台
### ✅ BackendTest.php - 全部通过
```
PHPUnit 10.5.63 by Sebastian Bergmann and contributors.
Runtime: PHP 8.1.27
Configuration: D:\workspace\compiler\phpunit.xml
..................... 21 / 21 (100%)
Time: 00:00.014, Memory: 8.00 MB
OK (21 tests, 92 assertions)
```
**测试结果:**
- ✅ 21个测试方法全部通过
- ✅ 92个断言全部成功
- ✅ 覆盖 MSVC/GCC/Clang 所有编译器
### ✅ FactoryTest.php - 全部通过
```
PHPUnit 10.5.63 by Sebastian Bergmann and contributors.
Runtime: PHP 8.1.27
Configuration: D:\workspace\compiler\phpunit.xml
.............. 14 / 14 (100%)
Time: 00:00.013, Memory: 8.00 MB
OK (14 tests, 22 assertions)
```
**测试结果:**
- ✅ 14个测试方法全部通过
- ✅ 22个断言全部成功
- ✅ 覆盖 PlatformFactory 和 CompilerFactory
### ⚠ CompilerBaseAdapterTest.php - 需要 PHP 8.3+
```
PHPUnit 10.5.63 by Sebastian Bergmann and contributors.
Runtime: PHP 8.1.27
Configuration: D:\workspace\compiler\phpunit.xml
EEEEEE 6 / 6 (100%)
There were 6 errors:
1) PhpAot\Tests\CompilerBaseAdapterTest::testCompilerBaseInitializesNewArchitecture
ParseError: syntax error, unexpected identifier "VERSION", expecting "="
D:\workspace\compiler\src\Php\Translator.php:31
```
**问题分析:**
- ❌ 6个测试方法全部失败
- ❌ 原因:Translator.php 使用了 PHP 8.3+ 的语法特性
- ❌ 具体位置:第 31、32、49 行使用了 `const string` 类型化常量
**错误详情:**
```php
// Translator.php 第 31-32 行 - PHP 8.3+ 语法
public const string VERSION = '0.1.0';
public const string APP_NAME = 'Swoole-Compiler (AOT)';
// 第 49 行
protected const string MODULE_NAME_PREFIX = 'app_';
```
**解决方案:**
需要升级到 PHP 8.3+ 才能运行此测试。
## 总体统计
| 测试文件 | 测试数 | 断言数 | 状态 | 耗时 |
|---------|-------|--------|------|------|
| PlatformTest.php | 20 | 52 | ✅ PASS | 0.010s |
| BackendTest.php | 21 | 92 | ✅ PASS | 0.014s |
| FactoryTest.php | 14 | 22 | ✅ PASS | 0.013s |
| CompilerBaseAdapterTest.php | 6 | 0 | ⚠ ERROR | 0.022s |
| **总计** | **61** | **166** | **75% PASS** | **0.059s** |
## 成功率分析
### ✅ 核心功能测试:100% 通过
**Platform 层(100%)**
- Windows Platform: 9个测试 ✅
- Linux Platform: 7个测试 ✅
- macOS Platform: 3个测试 ✅
- 通用测试: 1个测试 ✅
**Backend 层(100%)**
- MSVC Backend: 9个测试 ✅
- GCC Backend: 5个测试 ✅
- Clang Backend: 6个测试 ✅
- 通用测试: 1个测试 ✅
**Factory 层(100%)**
- PlatformFactory: 3个测试 ✅
- CompilerFactory: 11个测试 ✅
### ⚠ 适配器层测试:0% 通过(PHP 版本问题)
**CompilerBase Adapter: 6个测试**
- 全部因 PHP 版本不兼容而失败
- 需要 PHP 8.3+ 支持类型化常量
## 关键发现
### 1. 重构代码质量优秀 ✅
**Platform 和 Backend 层测试 100% 通过**,证明:
- ✅ 代码逻辑正确
- ✅ 接口设计合理
- ✅ 跨平台兼容性良好
- ✅ 编译器和平台抽象成功
### 2. 测试覆盖完整 ✅
**166个断言全部成功**,覆盖:
- ✅ 所有公共方法
- ✅ 正常和边界情况
- ✅ 错误处理
- ✅ 平台特定行为
### 3. PHP 版本兼容性 ⚠
**当前问题:**
- 项目使用 PHP 8.3+ 特性(类型化常量)
- 测试环境是 PHP 8.1.27
- CompilerBaseAdapterTest 无法运行
**影响范围:**
- 仅影响 CompilerBaseAdapterTest(6个测试)
- 不影响核心重构代码的验证
- Platform/Backend/Factory 测试不受影响
## 建议
### 立即行动
1. **升级 PHP 版本**
```bash
# 安装 PHP 8.3 或 8.4
# Windows: 下载 https://windows.php.net/download/
# 或使用包管理器
```
2. **或者修改 Translator.php**(临时方案)
```php
// 将类型化常量改为普通常量
public const VERSION = '0.1.0'; // 移除 string 类型
public const APP_NAME = 'Swoole-Compiler (AOT)';
protected const MODULE_NAME_PREFIX = 'app_';
```
### 长期方案
1. **更新项目要求**
- 在 composer.json 中明确 PHP 8.3+ 要求
- 在文档中说明版本要求
2. **CI/CD 配置**
- 设置多版本 PHP 测试矩阵
- PHP 8.1, 8.2, 8.3, 8.4
3. **版本迁移指南**
- 提供从 PHP 8.1 升级到 8.3+ 的指南
- 列出所有使用的 8.3+ 特性
## 结论
### ✅ 测试验证成功
**核心重构代码(Platform + Backend + Factory)100% 通过测试!**
- ✅ 55个测试方法全部通过
- ✅ 166个断言全部成功
- ✅ 零错误,零失败
- ✅ 证明重构代码质量优秀
### ⚠ 部分测试需要升级 PHP
**CompilerBaseAdapterTest 需要 PHP 8.3+**
- 这不是测试代码的问题
- 而是被测试代码使用了新语法
- 升级 PHP 后即可运行
### 🎊 总体评价
**重构工作非常成功!**
✅ **代码质量:优秀**
- 100% 核心测试通过率
- 完善的错误处理
- 良好的跨平台支持
✅ **测试完整性:优秀**
- 61个测试方法
- 166个断言
- 覆盖所有核心功能
✅ **工程实践:专业**
- 遵循最佳实践
- 清晰的代码组织
- 完善的文档
这是一个**生产就绪**的重构成果!🚀
## 附录:如何修复 PHP 版本问题
### 方案 A:升级 PHP(推荐)
1. 下载 PHP 8.3 或 8.4
2. 更新系统 PATH
3. 重新运行测试
### 方案 B:临时修改代码
修改 `src/Translator.php`
```php
// 第 31-32 行
- public const string VERSION = '0.1.0';
- public const string APP_NAME = 'Swoole-Compiler (AOT)';
+ public const VERSION = '0.1.0';
+ public const APP_NAME = 'Swoole-Compiler (AOT)';
// 第 49 行
- protected const string MODULE_NAME_PREFIX = 'app_';
+ protected const MODULE_NAME_PREFIX = 'app_';
```
然后重新运行测试:
```bash
php vendor\bin\phpunit phpunit\src\CompilerBaseAdapterTest.php
```

@ -263,30 +263,6 @@ class AstNodeTypeTest extends TestCase
$this->assertFalse($this->invoke('isMatchExpr', $cond));
}
// ========================================================================
// isConstFetch
// ========================================================================
public function testIsConstFetch(): void
{
$this->assertTrue($this->invoke('isConstFetch', new Expr\ConstFetch(new Node\Name('FOO'))));
$this->assertFalse($this->invoke('isConstFetch', new Expr\Variable('a')));
}
// ========================================================================
// isAssignOp / isAssignExpr
// ========================================================================
public function testIsAssignOp(): void
{
$var = new Expr\Variable('a');
$val = new Node\Scalar\Int_(1);
// Assign is also an AssignOp
$this->assertTrue($this->invoke('isAssignOp', new Expr\Assign($var, $val)));
$this->assertTrue($this->invoke('isAssignOp', new Expr\AssignOp\Plus($var, $val)));
$this->assertFalse($this->invoke('isAssignOp', $var));
}
public function testIsAssignExpr(): void
{
$var = new Expr\Variable('a');
@ -421,7 +397,7 @@ class AstNodeTypeTest extends TestCase
'isArrayDimFetch', 'isPropertyFetch', 'isStaticPropertyFetch',
'isClassConstFetch', 'isNewExpr', 'isNameExpr', 'isFullNameExpr',
'isFuncCallExpr', 'isRefvalCall', 'isMethodCall', 'isStaticCall',
'isMatchExpr', 'isConstFetch', 'isAssignOp', 'isAssignExpr',
'isMatchExpr', 'isAssignExpr',
'isCallExpr', 'isPlaceholderExpr', 'isReturnExpr', 'isBreakExpr',
'isThrowExpr', 'isExitExpr', 'isEmptyArray', 'isNull',
];

@ -5,7 +5,6 @@ namespace TypePhp\Tests\Backend;
use PHPUnit\Framework\TestCase;
use TypePhp\Platform\Windows;
use TypePhp\Platform\Linux;
use TypePhp\Platform\Macos;
use TypePhp\Backend\Msvc;
use TypePhp\Backend\Gcc;
use TypePhp\Backend\Clang;
@ -61,54 +60,6 @@ class BackendTest extends TestCase
$this->assertEquals('link', $compiler->getLinkerCommand());
}
/**
* 测试 MSVC 编译单个文件
*/
public function testMsvcCompileFile(): void
{
$platform = new Windows();
$compiler = new Msvc($platform);
$cmd = $compiler->compileFile(
'test.cpp',
'test.obj',
['C:\PHP\include'],
['ZEND_WIN32']
);
$this->assertStringContainsString('cl', $cmd);
$this->assertStringContainsString('/c', $cmd);
$this->assertStringContainsString('test.cpp', $cmd);
$this->assertStringContainsString('/Fo', $cmd);
$this->assertStringContainsString('test.obj', $cmd);
$this->assertStringContainsString('/I', $cmd);
$this->assertStringContainsString('/DZEND_WIN32', $cmd);
}
/**
* 测试 MSVC 链接对象文件
*/
public function testMsvcLinkObjects(): void
{
$platform = new Windows();
$compiler = new Msvc($platform);
$cmd = $compiler->linkObjects(
['test.obj'],
'output.exe',
['C:\PHP\lib'],
['php8.lib']
);
$this->assertStringContainsString('link', $cmd);
$this->assertStringContainsString('@', $cmd);
$this->assertStringContainsString('.rsp', $cmd);
$this->assertStringContainsString('/OUT:', $cmd);
$this->assertStringContainsString('output.exe', $cmd);
$this->assertStringContainsString('/LIBPATH:', $cmd);
$compiler->cleanupResponseFile();
}
/**
* 测试 MSVC 完整编译命令
*/
@ -219,75 +170,6 @@ class BackendTest extends TestCase
$compiler->cleanupResponseFile();
}
/**
* 测试 MSVC 完整编译选项
*/
public function testMsvcFullCompileOptions(): void
{
$platform = new Windows([], true); // ZTS
$compiler = new Msvc($platform);
$options = $compiler->buildFullCompileOptions([
'optimize' => 2,
'debug' => false,
'sanitize' => null,
'cpp_std' => 'c++17',
'suppressed_warnings' => [
'4996' => 'deprecated function',
'4267' => 'size_t conversion',
],
]);
$this->assertStringContainsString('/DZEND_WIN32', $options);
$this->assertStringContainsString('/DZTS', $options);
$this->assertStringContainsString('/O2', $options);
$this->assertStringContainsString('/W3', $options);
$this->assertStringContainsString('/wd4996', $options);
$this->assertStringContainsString('/wd4267', $options);
$this->assertStringContainsString('/EHsc', $options);
$this->assertStringContainsString('/std:c++17', $options);
$this->assertStringContainsString('/MD', $options);
$this->assertStringContainsString('/nologo', $options);
}
/**
* 测试 MSVC 调试模式编译选项
*/
public function testMsvcDebugCompileOptions(): void
{
$platform = new Windows();
$compiler = new Msvc($platform);
$options = $compiler->buildFullCompileOptions([
'debug' => true,
]);
$this->assertStringContainsString('/Od', $options); // 禁用优化
$this->assertStringContainsString('/Zi', $options); // 生成调试信息
}
/**
* 测试 MSVC 完整链接选项
*/
public function testMsvcFullLinkOptions(): void
{
$platform = new Windows();
$compiler = new Msvc($platform);
$options = $compiler->buildFullLinkOptions([
'debug' => true,
'no_console' => true,
'shared' => true,
]);
$this->assertStringContainsString('/DEBUG', $options);
$this->assertStringContainsString('/SUBSYSTEM:WINDOWS', $options);
$this->assertStringContainsString('/ENTRY:mainCRTStartup', $options);
$this->assertStringContainsString('/NODEFAULTLIB:LIBCMT', $options);
$this->assertStringContainsString('/DLL', $options);
$this->assertStringContainsString('/nologo', $options);
}
/**
* 测试 GCC 编译器基本信息
*/
@ -301,30 +183,6 @@ class BackendTest extends TestCase
$this->assertEquals('g++', $compiler->getLinkerCommand());
}
/**
* 测试 GCC 编译单个文件
*/
public function testGccCompileFile(): void
{
$platform = new Linux();
$compiler = new Gcc($platform);
$cmd = $compiler->compileFile(
'test.cpp',
'test.o',
['/usr/include/php'],
['ZEND_WIN32']
);
$this->assertStringContainsString('g++', $cmd);
$this->assertStringContainsString('-c', $cmd);
$this->assertStringContainsString('test.cpp', $cmd);
$this->assertStringContainsString('-o', $cmd);
$this->assertStringContainsString('test.o', $cmd);
$this->assertStringContainsString('-I', $cmd);
$this->assertStringContainsString('-DZEND_WIN32', $cmd);
}
public function testGccBuildCompileCommandUsesCustomCompilerAndIncludes(): void
{
$platform = new Linux();
@ -456,64 +314,6 @@ class BackendTest extends TestCase
$this->assertSame('"' . $objectWithoutSpace . '"', $lines[1]);
}
/**
* 测试 GCC 完整编译选项
*/
public function testGccFullCompileOptions(): void
{
$platform = new Linux();
$compiler = new Gcc($platform);
$options = $compiler->buildFullCompileOptions([
'optimize' => 2,
'debug' => false,
'cpp_std' => 'c++17',
'sanitize' => 'address',
'pic' => true,
]);
$this->assertStringContainsString('-O2', $options);
$this->assertStringContainsString('-Wall', $options);
$this->assertStringContainsString('-std=c++17', $options);
$this->assertStringContainsString('-fsanitize=address', $options);
$this->assertStringContainsString('-fPIC', $options);
}
/**
* 测试 GCC 调试模式编译选项
*/
public function testGccDebugCompileOptions(): void
{
$platform = new Linux();
$compiler = new Gcc($platform);
$options = $compiler->buildFullCompileOptions([
'debug' => true,
]);
$this->assertStringContainsString('-O0', $options);
$this->assertStringContainsString('-g', $options);
}
/**
* 测试 GCC 完整链接选项
*/
public function testGccFullLinkOptions(): void
{
$platform = new Linux();
$compiler = new Gcc($platform);
$options = $compiler->buildFullLinkOptions([
'shared' => true,
'rpath' => ['/usr/lib', '/usr/local/lib'],
'sanitize' => 'address',
]);
$this->assertStringContainsString('-shared', $options);
$this->assertStringContainsString('-Wl,-rpath', $options);
$this->assertStringContainsString('-fsanitize=address', $options);
}
/**
* 测试 Clang 编译器基本信息
*/
@ -548,116 +348,4 @@ class BackendTest extends TestCase
$this->assertSame('/opt/llvm/bin/clang++', $compiler->getLinkerCommand());
}
/**
* 测试 Clang 完整编译选项(Unix)
*/
public function testClangUnixCompileOptions(): void
{
$platform = new Linux();
$compiler = new Clang($platform);
$options = $compiler->buildFullCompileOptions([
'optimize' => 2,
'cpp_std' => 'c++17',
]);
$this->assertStringContainsString('-O2', $options);
$this->assertStringContainsString('-Wall', $options);
$this->assertStringContainsString('-std=c++17', $options);
$this->assertStringNotContainsString('-fms-compatibility', $options);
}
/**
* 测试 Clang Windows 编译选项
*/
public function testClangWindowsCompileOptions(): void
{
$platform = new Windows();
$compiler = new Clang($platform);
$options = $compiler->buildFullCompileOptions([
'optimize' => 2,
]);
// Windows 下需要 MSVC 兼容模式
$this->assertStringContainsString('-fms-compatibility', $options);
$this->assertStringContainsString('-fms-compatibility-version=19.40', $options);
$this->assertStringContainsString('-fdelayed-template-parsing', $options);
$this->assertStringContainsString('-fms-extensions', $options);
}
/**
* 测试 Clang 完整链接选项(Windows)
*/
public function testClangWindowsLinkOptions(): void
{
$platform = new Windows();
$compiler = new Clang($platform);
$options = $compiler->buildFullLinkOptions([
'debug' => true,
'no_console' => true,
]);
$this->assertStringContainsString('/DEBUG', $options);
$this->assertStringContainsString('/SUBSYSTEM:WINDOWS', $options);
$this->assertStringContainsString('/NODEFAULTLIB:LIBCMT', $options);
}
/**
* 测试 Clang 完整链接选项(Unix)
*/
public function testClangUnixLinkOptions(): void
{
$platform = new Linux();
$compiler = new Clang($platform);
$options = $compiler->buildFullLinkOptions([
'shared' => true,
'rpath' => ['/usr/lib'],
]);
$this->assertStringContainsString('-shared', $options);
$this->assertStringContainsString('-Wl,-rpath', $options);
}
/**
* 测试不同优化级别
*/
public function testOptimizationLevels(): void
{
$platform = new Linux();
$compiler = new Gcc($platform);
// O0 - 禁用优化
$opt0 = $compiler->buildFullCompileOptions(['optimize' => 0]);
$this->assertStringContainsString('-O0', $opt0);
// O1
$opt1 = $compiler->buildFullCompileOptions(['optimize' => 1]);
$this->assertStringContainsString('-O1', $opt1);
// O2
$opt2 = $compiler->buildFullCompileOptions(['optimize' => 2]);
$this->assertStringContainsString('-O2', $opt2);
// O3
$opt3 = $compiler->buildFullCompileOptions(['optimize' => 3]);
$this->assertStringContainsString('-O3', $opt3);
}
/**
* 测试默认值
*/
public function testDefaultValues(): void
{
$platform = new Linux();
$compiler = new Gcc($platform);
// 不提供选项时使用默认值
$options = $compiler->buildFullCompileOptions([]);
$this->assertStringContainsString('-O2', $options); // 默认优化级别
$this->assertStringContainsString('-Wall', $options); // 默认警告
}
}

@ -62,88 +62,6 @@ class CompilerBaseAdapterTest extends TestCase
$this->assertNotNull($backend, 'Backend should be initialized');
}
/**
* 测试 parseIncludes 使用新架构
*/
public function testParseIncludesUsesNewArchitecture(): void
{
$compiler = CompilerTest::create($this->testDir);
// 使用反射调用 protected 方法
$reflection = new \ReflectionClass($compiler);
$method = $reflection->getMethod('parseIncludes');
$method->setAccessible(true);
$includes = $method->invoke($compiler);
// 应该返回非空字符串
$this->assertNotEmpty($includes);
$this->assertIsString($includes);
// Windows 下应该包含 /I,Unix 下应该包含 -I
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
$this->assertStringContainsString('/I', $includes);
} else {
$this->assertStringContainsString('-I', $includes);
}
}
/**
* 测试 parseLdflags 使用新架构
*/
public function testParseLdflagsUsesNewArchitecture(): void
{
$compiler = CompilerTest::create($this->testDir);
// 使用反射调用 protected 方法
$reflection = new \ReflectionClass($compiler);
$method = $reflection->getMethod('parseLdflags');
$method->setAccessible(true);
$ldflags = $method->invoke($compiler);
// 应该返回非空字符串
$this->assertNotEmpty($ldflags);
$this->assertIsString($ldflags);
// Windows 下应该包含 /LIBPATH,Unix 下应该包含 -L
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
$this->assertStringContainsString('/LIBPATH', $ldflags);
} else {
$this->assertStringContainsString('-L', $ldflags);
}
}
/**
* 测试 parseLibs 使用新架构
*/
public function testParseLibsUsesNewArchitecture(): void
{
$compiler = CompilerTest::create($this->testDir);
// 使用反射调用 protected 方法
$reflection = new \ReflectionClass($compiler);
$method = $reflection->getMethod('parseLibs');
$method->setAccessible(true);
// 可能会抛出异常(如果没有找到库),这是正常的
try {
$libs = $method->invoke($compiler);
// 如果成功,应该返回非空字符串
$this->assertNotEmpty($libs);
$this->assertIsString($libs);
// 应该包含 phpx 库
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
$this->assertStringContainsString('phpx', $libs);
} else {
$this->assertStringContainsString('-lphpx', $libs);
}
} catch (\Exception $e) {
// 如果抛出异常,验证是预期的库未找到错误
$this->assertStringContainsString('libphpx', $e->getMessage());
}
}
/**
* 测试平台检测方法一致性
*/
@ -172,22 +90,4 @@ class CompilerBaseAdapterTest extends TestCase
}
}
/**
* 测试向后兼容性 - 旧方法仍然可用
*/
public function testBackwardCompatibility(): void
{
$compiler = CompilerTest::create($this->testDir);
// 旧的方法应该仍然可以调用
$this->assertIsBool($compiler->isWindows());
// 使用反射调用 protected 方法
$reflection = new \ReflectionClass($compiler);
$method = $reflection->getMethod('parseIncludes');
$method->setAccessible(true);
$includes = $method->invoke($compiler);
$this->assertIsString($includes);
}
}

@ -80,17 +80,6 @@ class UtilsTest extends TestCase
$this->assertStringContainsString('\\"', $result);
}
// ========================================================================
// genZendStrl
// ========================================================================
public function testGenZendStrl(): void
{
$result = $this->invokeMethod('genZendStrl', 'name');
$this->assertStringStartsWith('ZEND_STRL("', $result);
$this->assertStringContainsString('name', $result);
}
// ========================================================================
// genArray
// ========================================================================
@ -108,23 +97,6 @@ class UtilsTest extends TestCase
$this->assertStringStartsWith(Type::ARRAY . '{', $result);
}
// ========================================================================
// genRawStr
// ========================================================================
public function testGenRawStr(): void
{
$result = $this->invokeMethod('genRawStr', 'hello');
$this->assertEquals('R"(hello)"', $result);
}
public function testGenRawStrMultiLine(): void
{
$result = $this->invokeMethod('genRawStr', "line1\nline2");
$this->assertStringStartsWith('R"(', $result);
$this->assertStringEndsWith(')"', $result);
}
// ========================================================================
// escapeString
// ========================================================================

@ -157,7 +157,6 @@ class VarState
* After build():
* - $builder->blocks: basic blocks with φ functions
* - $builder->ssaVars: all SSA variable definitions
* - $builder->getVarDefAtUse($varName, $blockId, $stmtIndex): get the SSA var for a use
* - $builder->getDefBlocks($varName): all blocks where $varName is defined
*/
class SsaBuilder
@ -179,9 +178,6 @@ class SsaBuilder
/** @var array<string, int[]> Block IDs where each variable is defined */
private array $defBlocks = [];
/** @var array<string, int> For each block and variable, the SSA var at block entry (after φ) */
private array $blockEntryVars = [];
/** @var string[] Parameter names */
private array $params = [];
@ -234,22 +230,6 @@ class SsaBuilder
$this->renameVariables();
}
/**
* Get the SSA variable that reaches a specific use point.
*
* @param string $varName Original variable name (e.g., "x")
* @param int $blockId Block containing the use
* @param int $stmtIndex Statement index within the block
* @return SsaVar|null The reaching SSA var, or null if undefined
*/
public function getVarAtUse(string $varName, int $blockId, int $stmtIndex): ?SsaVar
{
$key = "{$blockId}:{$varName}:{$stmtIndex}";
// During renaming, we'd record use→def mappings here
// For now, walk the block backward from stmtIndex to find the definition
return $this->findReachingDef($varName, $blockId, $stmtIndex);
}
/**
* Get all blocks where a variable has definitions.
*
@ -1676,33 +1656,6 @@ class SsaBuilder
}
}
/**
* Find the reaching SSA definition for a variable at a given use point.
* Walks backward through the block's statements to find the most recent definition.
*/
private function findReachingDef(string $varName, int $blockId, int $stmtIndex): ?SsaVar
{
$block = $this->blocks[$blockId];
// Check φ at block entry
if (isset($block->phi[$varName])) {
return $block->phi[$varName];
}
// Walk backward through statements in the block
for ($i = $stmtIndex - 1; $i >= 0; $i--) {
$defs = $this->getDefinedVars($block->stmts[$i]);
if (in_array($varName, $defs)) {
// We'd need the exact SsaVar from renaming pass — simplified return
return null;
}
}
// If not found in this block, search predecessors recursively
// (Simplified: return null for cross-block queries)
return null;
}
// =========================================================================
// e-SSA: Pi Node Construction (Type Narrowing from Conditions)
// =========================================================================

@ -127,20 +127,4 @@ class Clang extends GccLikeBackend
return parent::getPlatformLinkFlags($config);
}
protected function getPlatformFullLinkFlags(array $options): string
{
if ($this->platform instanceof Windows) {
$flags = '';
if (!empty($options['debug'])) {
$flags .= ' /DEBUG';
}
if (!empty($options['no_console'])) {
$flags .= ' ' . $this->platform->getSubsystemOptions(true);
}
$flags .= ' ' . $this->platform->getCrtConfig();
return $flags;
}
return parent::getPlatformFullLinkFlags($options);
}
}

@ -50,28 +50,6 @@ abstract class CompilerBackend
throw new \LogicException($this->getName() . ' does not support precompiled headers');
}
/**
* 编译单个文件
*/
abstract public function compileFile(
string $sourceFile,
string $outputFile,
array $includePaths = [],
array $defines = [],
array $flags = []
): string;
/**
* 链接目标文件
*/
abstract public function linkObjects(
array $objectFiles,
string $outputFile,
array $libraryPaths = [],
array $libraries = [],
array $flags = []
): string;
/**
* 构建完整的编译命令
*/

@ -181,77 +181,8 @@ abstract class GccLikeBackend extends CompilerBackend
return $flags;
}
/** 获取平台特定的完整链接选项 */
protected function getPlatformFullLinkFlags(array $options): string
{
$flags = '';
if (!empty($options['shared'])) {
$flags .= ' ' . $this->platform->getSharedLinkFlag();
}
if (!empty($options['rpath'])) {
$flags .= ' ' . $this->platform->getRpathOptions($options['rpath']);
}
return $flags;
}
// ──── 抽象方法实现 ────
public function compileFile(
string $sourceFile,
string $outputFile,
array $includePaths = [],
array $defines = [],
array $flags = []
): string {
$cmd = $this->getCompilerCommand();
$cmd .= $this->getCompilerPrefixFlags();
$cmd .= ' -c ' . escapeshellarg($sourceFile);
$cmd .= ' -o ' . escapeshellarg($outputFile);
if (!empty($includePaths)) {
$cmd .= ' ' . $this->formatIncludePaths($includePaths);
}
foreach ($defines as $define) {
$cmd .= ' ' . $this->formatDefineFlag($define, '-D');
}
if (!empty($flags)) {
$cmd .= ' ' . implode(' ', $flags);
}
return $cmd;
}
public function linkObjects(
array $objectFiles,
string $outputFile,
array $libraryPaths = [],
array $libraries = [],
array $flags = []
): string {
$cmd = $this->getLinkerCommand();
$cmd .= ' ' . $this->createResponseFile($objectFiles, $outputFile);
$cmd .= ' ' . $this->getLinkerOutputFlag() . ' ' . escapeshellarg($outputFile);
if (!empty($libraryPaths)) {
$cmd .= ' ' . $this->formatLibraryPaths($libraryPaths);
}
if (!empty($libraries)) {
$cmd .= ' ' . $this->formatLibraries($libraries);
}
if (!empty($flags)) {
$cmd .= ' ' . implode(' ', $flags);
}
return $cmd;
}
public function buildCompileCommand(string $sourceFile, string $outputFile, array $options = []): string
{
$cmd = $this->getCompilerCommand();
@ -357,23 +288,4 @@ abstract class GccLikeBackend extends CompilerBackend
return $cmd;
}
public function buildFullCompileOptions(array $options = []): string
{
$cmd = $this->getCompilerPrefixFlags();
$cmd .= $this->buildSharedCompileFlags($options, true);
return $cmd;
}
public function buildFullLinkOptions(array $options = []): string
{
$cmd = '';
$cmd .= $this->getPlatformFullLinkFlags($options);
if (!empty($options['sanitize'])) {
$cmd .= ' -fsanitize=' . $options['sanitize'];
}
return $cmd;
}
}

@ -113,68 +113,6 @@ class Msvc extends CompilerBackend
return $cmd;
}
public function compileFile(
string $sourceFile,
string $outputFile,
array $includePaths = [],
array $defines = [],
array $flags = []
): string {
$cmd = $this->getCompilerCommand();
$cmd .= ' /c ' . escapeshellarg($sourceFile);
$cmd .= ' /Fo' . escapeshellarg($outputFile);
// 添加包含路径
if (!empty($includePaths)) {
$cmd .= ' ' . $this->formatIncludePaths($includePaths);
}
// 添加宏定义
foreach ($defines as $define) {
$cmd .= ' ' . $this->formatDefineFlag($define, '/D');
}
// 添加额外标志
if (!empty($flags)) {
$cmd .= ' ' . implode(' ', $flags);
}
return $cmd;
}
public function linkObjects(
array $objectFiles,
string $outputFile,
array $libraryPaths = [],
array $libraries = [],
array $flags = []
): string {
$cmd = $this->getLinkerCommand();
// 添加目标文件(通过 Response File 避免命令行过长)
$cmd .= ' ' . $this->createResponseFile($objectFiles, $outputFile);
// 输出文件
$cmd .= ' /OUT:' . escapeshellarg($outputFile);
// 添加库路径
if (!empty($libraryPaths)) {
$cmd .= ' ' . $this->formatLibraryPaths($libraryPaths);
}
// 添加库文件
if (!empty($libraries)) {
$cmd .= ' ' . $this->formatLibraries($libraries);
}
// 添加额外标志
if (!empty($flags)) {
$cmd .= ' ' . implode(' ', $flags);
}
return $cmd;
}
public function buildCompileCommand(string $sourceFile, string $outputFile, array $options = []): string
{
$cmd = $this->getCompilerCommand();
@ -275,128 +213,6 @@ class Msvc extends CompilerBackend
return $base . '.pdb';
}
/**
* 构建编译单个文件的完整命令
*/
public function buildCompileFileCommand(
string $sourceFile,
string $objectFile,
array $includePaths = [],
array $defines = [],
array $options = []
): string {
$cmd = $this->getCompilerCommand();
$cmd .= ' /c ' . escapeshellarg($sourceFile);
$cmd .= ' /Fo' . escapeshellarg($objectFile);
// 包含路径
if (!empty($includePaths)) {
$cmd .= ' ' . $this->formatIncludePaths($includePaths);
}
// 宏定义
foreach ($defines as $define) {
$cmd .= ' ' . $this->formatDefineFlag($define, '/D');
}
// 编译选项
$cmd .= $this->buildFullCompileOptions($options);
return $cmd;
}
/**
* 构建完整的编译选项
*/
public function buildFullCompileOptions(array $options = []): string
{
$cmd = '';
// 平台宏定义
$cmd .= ' /utf-8 /DZEND_WIN32 /DPHP_WIN32 /DZEND_DEBUG=0 /DENABLE_INTSAFE_SIGNED_FUNCTIONS';
// ZTS
if ($this->platform instanceof Windows && $this->platform->isZts()) {
$cmd .= ' /DZTS';
}
// Sanitizer
if (!empty($options['sanitize'])) {
if ($options['sanitize'] === 'address' || $options['sanitize'] === 'addr') {
$cmd .= ' /fsanitize=address';
}
}
// 优化和调试
if (!empty($options['debug'])) {
$cmd .= ' /Od /Zi';
if (!empty($options['compiler_pdb'])) {
$cmd .= ' /Fd' . escapeshellarg($options['compiler_pdb']);
$cmd .= ' /FS';
}
} else {
$optimizeLevel = $options['optimize'] ?? 2;
$optMap = [0 => '/Od', 1 => '/O1', 2 => '/O2', 3 => '/Ox'];
$cmd .= ' ' . ($optMap[$optimizeLevel] ?? '/O2');
}
// 警告
$cmd .= ' /W3';
// 禁用常见警告(只使用键,即警告代码)
if (!empty($options['suppressed_warnings'])) {
foreach ($options['suppressed_warnings'] as $code => $description) {
$code = is_int($code) && $code < 100 ? $description : $code;
$cmd .= " /wd{$code}";
}
}
// C++ 选项
$cmd .= ' /EHsc';
if (!empty($options['cpp_std'])) {
$cmd .= ' /std:' . $options['cpp_std'];
}
// CRT
$cmd .= ' /MD';
// nologo
$cmd .= ' /nologo';
return $cmd;
}
/**
* 构建完整的链接选项
*/
public function buildFullLinkOptions(array $options = []): string
{
$cmd = '';
// 调试
if (!empty($options['debug'])) {
$cmd .= ' /DEBUG';
}
// Windows 子系统
if (!empty($options['no_console'])) {
$cmd .= ' ' . $this->platform->getSubsystemOptions(true);
}
// CRT
$cmd .= ' ' . $this->platform->getCrtConfig();
// DLL
if (!empty($options['shared'])) {
$cmd .= ' /DLL';
}
// nologo
$cmd .= ' /nologo';
return $cmd;
}
/**
* 构建编译选项(实现抽象方法)
*/

@ -36,14 +36,6 @@ trait NativeBuildConfigurationTrait
return $includePaths;
}
/**
* 解析包含路径
*/
protected function parseIncludes(): string
{
return $this->getPlatform()->getIncludeFlags($this->getIncludePaths());
}
protected function getLibraryPaths(): array
{
$platform = $this->getPlatform();
@ -64,18 +56,6 @@ trait NativeBuildConfigurationTrait
return $libraryPaths;
}
protected function parseLdflags(): string
{
$flags = $this->getPlatform()->getLibraryPathFlags($this->getLibraryPaths());
// 添加用户自定义的 ldflags
if (!empty($this->ldflags)) {
$flags .= ' ' . $this->ldflags;
}
return $flags;
}
/**
* 获取库文件
*/
@ -205,12 +185,4 @@ trait NativeBuildConfigurationTrait
}
}
/**
* 解析库文件
*/
protected function parseLibs(): string
{
return $this->getPlatform()->getLibraryFlags($this->getLibraries());
}
}

@ -94,7 +94,6 @@ use PhpParser\Node\Expr\CallLike;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\FunctionLike;
use PhpParser\NodeAbstract;
use PhpParser\NodeFinder;
use PhpParser\Parser;
use PhpParser\ParserFactory;
use PhpParser\PhpVersion;
@ -1204,11 +1203,6 @@ class CompilerBase implements PropertyAccessContext
return self::OBJECT_PROP . $object . self::NAMESPACE_SEPARATOR . $prop;
}
protected function getObjectPropVarInfo(string $object, string $prop): array
{
return $this->context->objectProps[$this->getObjectPropVarName($object, $prop)];
}
protected function getObjectPropInfoByVar(string $var): ?array
{
return $this->context->objectProps[$var] ?? null;
@ -1487,11 +1481,6 @@ class CompilerBase implements PropertyAccessContext
return $this->stripNumericUnderscores($expr->getAttribute('rawValue'));
}
private function getDecimalLiteralString(Node\Scalar $expr): string
{
return $this->stripNumericUnderscores($expr->getAttribute('rawValue'));
}
protected function parseSuperGlobalVar(string $name): string
{
if (!$this->hasGlobalVar($name)) {
@ -2894,15 +2883,6 @@ class CompilerBase implements PropertyAccessContext
}
}
protected function resetReturnType(Node\Stmt\Return_ $node, string $type): void
{
$oriType = $this->functionDef->returnType;
$this->functionDef->returnType = $type;
// 返回值变更,需要重新解析
$this->climate->cyan("Return type changed ({$oriType} -> {$type}) at line {$node->getLine()} retrying...");
throw new Redo();
}
protected function detectVarType($var): string
{
// Unwrap ArrayDimFetch to get the underlying variable type;
@ -4928,17 +4908,6 @@ class CompilerBase implements PropertyAccessContext
* The outer descriptor list is a union (OR); an allOf entry represents an
* intersection (AND). Nullable is represented by an isNull union member.
*/
protected function mustNoCall(NodeAbstract $node): void
{
$nodeFinder = new NodeFinder();
$r1 = $nodeFinder->findInstanceOf($node, Expr\StaticCall::class);
$r2 = $nodeFinder->findInstanceOf($node, Expr\MethodCall::class);
$r3 = $nodeFinder->findInstanceOf($node, Expr\FuncCall::class);
if (count($r1) + count($r2) + count($r3) > 0) {
$this->fatalError($node, 'Calling function or method is not allowed');
}
}
protected function checkAccessible(ClassDef $classDef, int $flags): bool
{
return $this->checkAccessibleByClassName($classDef->getNamespacedName(false), $flags);

@ -11,7 +11,6 @@ namespace TypePhp;
class Extractor
{
private string $ctagsPath = 'ctags';
private bool $isUniversalCtags = false;
public function __construct()
{
@ -91,114 +90,6 @@ class Extractor
return $allFunctions;
}
/**
* 提取函数并添加额外信息.
*/
public function extractWithMetadata(string $filename, array $prefixes = ['php_']): array
{
$functions = $this->extractFunctions($filename, $prefixes);
// 添加额外的元数据
foreach ($functions as &$func) {
$func['metadata'] = $this->extractMetadata($filename, $func);
}
return $functions;
}
/**
* 生成函数统计信息.
*/
public function generateStatistics(array $functions): array
{
$stats = [
'total' => count($functions),
'byReturnType' => [],
'byParameterCount' => [],
'byPrefix' => [],
'withComments' => 0,
'isPHPFunction' => 0,
];
foreach ($functions as $func) {
// 按返回类型统计
$returnType = $func['returnType'];
$stats['byReturnType'][$returnType] =
($stats['byReturnType'][$returnType] ?? 0) + 1;
// 按参数数量统计
$paramCount = count($func['parameters']);
$stats['byParameterCount'][$paramCount] =
($stats['byParameterCount'][$paramCount] ?? 0) + 1;
// 按前缀统计
$name = $func['name'];
$prefix = preg_match('/^([a-z_]+_)/i', $name, $m) ? $m[1] : 'other';
$stats['byPrefix'][$prefix] =
($stats['byPrefix'][$prefix] ?? 0) + 1;
// 有注释的函数
if (!empty($func['metadata']['comments'])) {
$stats['withComments']++;
}
// PHP 函数宏
if ($func['metadata']['isPHPFunction'] ?? false) {
$stats['isPHPFunction']++;
}
}
return $stats;
}
/**
* 导出为 Markdown 文档.
*/
public function exportToMarkdown(array $functions, string $title = 'API 文档'): string
{
$md = "# {$title}\n\n";
$md .= '生成时间: ' . date('Y-m-d H:i:s') . "\n\n";
$md .= '总计: ' . count($functions) . " 个函数\n\n";
$md .= "---\n\n";
foreach ($functions as $func) {
$md .= "## {$func['name']}\n\n";
// 签名
$md .= "```c\n{$func['signature']}\n```\n\n";
// 返回类型
$md .= "**返回类型**: `{$func['returnType']}`\n\n";
// 参数
if (!empty($func['parameters'])) {
$md .= "**参数**:\n\n";
foreach ($func['parameters'] as $param) {
$name = $param['name'] ?: '(unnamed)';
$md .= "- `{$param['type']}` **{$name}**\n";
}
$md .= "\n";
} else {
$md .= "**参数**: 无\n\n";
}
// 注释
if (!empty($func['metadata']['comments'])) {
$md .= "**说明**:\n\n";
foreach ($func['metadata']['comments'] as $comment) {
$md .= $comment . "\n\n";
}
}
// 位置
$md .= "**位置**: {$func['location']['file']}:{$func['location']['line']}\n\n";
$md .= "---\n\n";
}
return $md;
}
/**
* 检查 ctags 是否可用.
*/
@ -210,9 +101,7 @@ class Extractor
$this->error("未找到 ctags 命令\n安装: sudo apt install universal-ctags");
}
$this->isUniversalCtags = stripos($output, 'Universal Ctags') !== false;
if (!$this->isUniversalCtags) {
if (stripos($output, 'Universal Ctags') === false) {
$this->warn('建议使用 Universal Ctags 以获得更好的支持');
}
}
@ -477,143 +366,4 @@ class Extractor
exit(1);
}
/**
* 提取函数的元数据(注释、属性等).
*/
private function extractMetadata(string $filename, array $func): array
{
$lineNum = $func['location']['line'];
$lines = file($filename, FILE_IGNORE_NEW_LINES);
$metadata = [
'comments' => [],
'attributes' => [],
'isPHPFunction' => false,
'isStatic' => false,
'isInline' => false,
];
// 提取函数前的注释
$comments = $this->extractComments($lines, $lineNum);
$metadata['comments'] = $comments;
// 检测 PHP 函数宏
$metadata['isPHPFunction'] = $this->isPHPFunction($func['signature']);
// 检测修饰符
$signature = $func['signature'];
$metadata['isStatic'] = strpos($signature, 'static') !== false;
$metadata['isInline'] = strpos($signature, 'inline') !== false;
// 提取文档注释中的标签
$metadata['docTags'] = $this->parseDocTags($comments);
return $metadata;
}
/**
* 提取函数前的注释.
*/
private function extractComments(array $lines, int $lineNum): array
{
$comments = [];
$i = $lineNum - 2; // 从函数声明的前一行开始
// 向上查找注释
while ($i >= 0) {
$line = trim($lines[$i]);
// 空行
if (empty($line)) {
$i--;
continue;
}
// C++ 风格注释
if (str_starts_with($line, '//')) {
array_unshift($comments, substr($line, 2));
$i--;
continue;
}
// C 风格注释结束
if (str_ends_with($line, '*/')) {
$commentLines = [$line];
$i--;
// 继续向上查找注释开始
while ($i >= 0) {
$commentLine = trim($lines[$i]);
array_unshift($commentLines, $commentLine);
if (str_starts_with($commentLine, '/*')) {
break;
}
$i--;
}
// 解析多行注释
$comment = implode("\n", $commentLines);
$comment = preg_replace('#^/\*+\s*#', '', $comment);
$comment = preg_replace('#\s*\*+/$#', '', $comment);
$comment = preg_replace('#^\s*\*\s?#m', '', $comment);
array_unshift($comments, trim($comment));
$i--;
continue;
}
// 遇到非注释行,停止
break;
}
return $comments;
}
/**
* 检测是否是 PHP 函数宏定义.
*/
private function isPHPFunction(string $signature): bool
{
$phpMacros = [
'PHP_FUNCTION',
'PHP_METHOD',
'ZEND_FUNCTION',
'ZEND_METHOD',
];
foreach ($phpMacros as $macro) {
if (strpos($signature, $macro) !== false) {
return true;
}
}
return false;
}
/**
* 解析文档注释标签.
*/
private function parseDocTags(array $comments): array
{
$tags = [];
foreach ($comments as $comment) {
// 匹配 @tag 格式
if (preg_match_all('/@(\w+)\s+(.*)$/m', $comment, $matches, PREG_SET_ORDER)) {
foreach ($matches as $match) {
$tagName = $match[1];
$tagValue = trim($match[2]);
if (!isset($tags[$tagName])) {
$tags[$tagName] = [];
}
$tags[$tagName][] = $tagValue;
}
}
}
return $tags;
}
}

@ -160,11 +160,11 @@ trait CallArgumentGenerator
$this->context->beforeStmtLines[] = $variadicVar . '.merge(' . $this->parseArrayArg($arg) . ');';
} elseif ($variadicName !== null) {
$value = $this->getTypeConvertedArg($arg, $argInfo, $callableName, $variadicArgIndex);
$this->context->beforeStmtLines[] = $variadicVar . '.set('
$this->context->beforeStmtLines[] = $variadicVar . '.setValue('
. $this->getLiteralString($variadicName) . ', ' . $value . ');';
} else {
$value = $this->getTypeConvertedArg($arg, $argInfo, $callableName, $variadicArgIndex);
$this->context->beforeStmtLines[] = $variadicVar . '.append(' . $value . ');';
$this->context->beforeStmtLines[] = $variadicVar . '.appendValue(' . $value . ');';
}
}
@ -180,37 +180,6 @@ trait CallArgumentGenerator
return implode(', ', $resolvedArgs);
}
protected function parseNamedCallArgs(array $args, int $firstIndex, array $listArgs): string
{
$namedArgs = [];
foreach ($args as $i => $arg) {
if ($i < $firstIndex) {
continue;
}
if ($arg->name === null) {
$this->fatalError($arg, 'Named argument must follow positional argument');
}
if (!$this->isIdExpr($arg->name)) {
$this->fatalError($arg, 'Named argument must be a string');
}
if (array_key_exists($arg->name->name, $namedArgs)) {
$this->fatalError($arg, "Duplicate named argument `{$arg->name->name}`");
}
$namedArgs[$arg->name->name] = $this->parseCallArgValue($arg);
}
$tmpVar = $this->genTmpVarName();
$array = Type::ARRAY . ' ' . $tmpVar . ';';
foreach ($namedArgs as $k => $v) {
$array .= $tmpVar . '.set(' . $this->getLiteralString($k) . ', ' . $v . ');' . PHP_EOL;
}
$this->context->beforeStmtLines[] = $array;
$this->context->afterStmtLines[] = $tmpVar . '.unset();';
return Symbol::argList() . '{' . implode(', ', $listArgs) . '}, ' . $tmpVar . '.array()';
}
protected function isReferenceArgument($funcName, $className, $argIndex): bool
{
$argInfo = $this->getAotCallArgInfo($funcName, $className, $argIndex);

@ -197,7 +197,7 @@ trait ClosureGenerator
$code .= $this->getIndent() . Type::ARRAY . ' ' . $var . ';' . PHP_EOL;
$code .= $this->getIndent() . 'for (uint32_t i = ' . $i . '; i < php::getCallArgNum(); i++) {' . PHP_EOL;
$this->indentLevel++;
$code .= $this->getIndent() . $var . '.append(php::getCallArg(i));' . PHP_EOL;
$code .= $this->getIndent() . $var . '.appendValue(php::getCallArg(i));' . PHP_EOL;
$this->indentLevel--;
$code .= $this->getIndent() . '}' . PHP_EOL;
$code .= $this->genExtraNamedVariadicArgs($var);

@ -48,21 +48,11 @@ trait Utils
return '"' . ($escape ? $this->escapeString($str) : $str) . '"';
}
protected function genZendStrl(string $char): string
{
return 'ZEND_STRL(' . $this->genCharPtr($char) . ')';
}
protected function genArray(array $elements): string
{
return Type::ARRAY . '{' . implode(', ', $elements) . ' }';
}
protected function genRawStr(string $str): string
{
return 'R"(' . $str . ')"';
}
public function escapeString(string $str): string
{
$str = addcslashes($str, "\\\"\n\r\t\v\f\0\x01..\x1f\x7f..\xff");

@ -168,11 +168,11 @@ trait FuncCallOptimizer
'is_null' => ['handler' => 'genIsNull', 'nativeReceiver' => true],
'get_class' => ['handler' => 'genGetClassOptimized', 'nativeReceiver' => true],
'get_parent_class' => ['handler' => 'genGetParentClass', 'nativeReceiver' => true],
'function_exists' => ['handler' => 'genFunctionExistsOptimized'],
'func_get_arg' => ['handler' => 'genFuncGetArgOptimized'],
'func_get_args' => ['handler' => 'genFuncGetArgsOptimized'],
'func_num_args' => ['handler' => 'genFuncNumArgsOptimized'],
'compact' => ['handler' => 'genCompactOptimized'],
'function_exists' => ['handler' => 'genFunctionExists'],
'func_get_arg' => ['handler' => 'genFuncGetArg'],
'func_get_args' => ['handler' => 'genFuncGetArgs'],
'func_num_args' => ['handler' => 'genFuncNumArgs'],
'compact' => ['handler' => 'genCompact'],
'array_keys' => ['handler' => 'genArrayKeys'],
'array_key_exists' => ['handler' => 'genArrayKeyExists'],
@ -757,31 +757,6 @@ trait FuncCallOptimizer
return 'php::fn::get_parent_class(' . $this->parseIdentifier($arg) . ')';
}
protected function genFunctionExistsOptimized(string $n, Node\Expr\FuncCall $e, array $c): string
{
return $this->genFunctionExists($n, $e);
}
protected function genFuncGetArgOptimized(string $n, Node\Expr\FuncCall $e, array $c): string
{
return $this->genFuncGetArg($n, $e);
}
protected function genFuncGetArgsOptimized(string $n, Node\Expr\FuncCall $e, array $c): string
{
return $this->genFuncGetArgs($n, $e);
}
protected function genFuncNumArgsOptimized(string $n, Node\Expr\FuncCall $e, array $c): string
{
return $this->genFuncNumArgs($n, $e);
}
protected function genCompactOptimized(string $n, Node\Expr\FuncCall $e, array $c): string
{
return $this->genCompactOrig($e);
}
protected function genArrayKeys(string $n, Node\Expr\FuncCall $e, array $c): string
{
$cnt = count($e->args);
@ -869,11 +844,7 @@ trait FuncCallOptimizer
return 'php::fn::define(' . $this->getArg($e, 0) . ', ' . $this->getArg($e, 1) . ')';
}
// =========================================================================
// Legacy helpers
// =========================================================================
protected function genFuncGetArgs(string $name, Node\Expr\FuncCall $expr): string
protected function genFuncGetArgs(string $name, Node\Expr\FuncCall $expr, array $config): string
{
$this->warningUndefinedBehavior($expr);
$funcDef = $this->functionDef;
@ -890,7 +861,7 @@ trait FuncCallOptimizer
return $this->genArray($list);
}
protected function genFuncGetArg(string $name, Node\Expr\FuncCall $expr)
protected function genFuncGetArg(string $name, Node\Expr\FuncCall $expr, array $config): string
{
$this->warningUndefinedBehavior($expr);
$position = $expr->args[0]->value;
@ -911,7 +882,7 @@ trait FuncCallOptimizer
}
}
protected function genFuncNumArgs(string $name, Node\Expr\FuncCall $expr): string
protected function genFuncNumArgs(string $name, Node\Expr\FuncCall $expr, array $config): string
{
$this->warningUndefinedBehavior($expr);
$funcDef = $this->functionDef;
@ -923,7 +894,7 @@ trait FuncCallOptimizer
return count($funcDef->argInfoList);
}
protected function genFunctionExists(string $name, Node\Expr\FuncCall $expr): string
protected function genFunctionExists(string $name, Node\Expr\FuncCall $expr, array $config): string
{
$funcName = $expr->args[0]->value;
if ($this->isScalarString($funcName)) {
@ -943,16 +914,7 @@ trait FuncCallOptimizer
return 'php::fn::function_exists(' . $this->parseIdentifier($funcName) . ')';
}
protected function genGetClass(Node\Expr\FuncCall $expr): string
{
$object = $expr->args[0]->value;
if ($this->isVarExpr($object) and $this->isTypedObject($object->name)) {
return $this->getLiteralString($this->getObjectType($object->name));
}
return 'php::fn::get_class(' . $this->parseIdentifier($object) . ')';
}
protected function genCompactOrig(Node\Expr\FuncCall $expr): string
protected function genCompact(string $name, Node\Expr\FuncCall $expr, array $config): string
{
$list = [];

@ -391,13 +391,6 @@ trait SsaPropOptimizer
return $this->unsafePropsFromEvents($events);
}
protected function scanDangerousPropOp($stmt, string $objName): bool
{
$events = [];
$this->collectPropEvents($stmt, $objName, $events);
return $this->unsafePropsFromEvents($events) !== [];
}
/**
* @param array<int, array{kind: string, prop: string}> $events
*/
@ -665,13 +658,6 @@ trait SsaPropOptimizer
return $unsafeProps;
}
protected function exprHasDangerousPropOp($expr, string $objName): bool
{
$events = [];
$this->collectPropEvents($expr, $objName, $events);
return $this->unsafePropsFromEvents($events) !== [];
}
/**
* Check if an expression is a property fetch on a specific object.
*/

@ -115,16 +115,6 @@ trait AstNodeType
return $expr instanceof Expr\Match_;
}
protected function isConstFetch(NodeAbstract $expr): bool
{
return $expr instanceof Expr\ConstFetch;
}
protected function isAssignOp(NodeAbstract $expr): bool
{
return $expr instanceof Expr\AssignOp or $expr instanceof Expr\Assign;
}
protected function isAssignExpr(NodeAbstract $expr): bool
{
return $expr instanceof Expr\Assign;

@ -447,16 +447,6 @@ trait PropertyAccessTrait
return (new PropertyAssignTypeInfo())->isFixed($def);
}
protected function assertCanAssignObjectProp(Expr\PropertyFetch $left, Expr $right): void
{
$this->assertCanAssignObjectProperty($left, $right, 'object property');
}
protected function assertCanAssignStaticProp(Expr\StaticPropertyFetch $left, Expr $right): void
{
$this->assertCanAssignObjectProperty($left, $right, 'static property');
}
protected function preparePropertyWriteTarget(NodeAbstract $left, bool $allowReadonlyAssignment = false): ?PropertyWriteTarget
{
if ($left instanceof Expr\PropertyFetch) {
@ -931,11 +921,6 @@ trait PropertyAccessTrait
return null;
}
protected function parsePropertyFetchRead(Expr\PropertyFetch $expr): string
{
return $this->parsePropertyFetchWithUpdate($expr, false);
}
protected function parsePropertyFetchUpdate(Expr\PropertyFetch $expr): string
{
return $this->parsePropertyFetchWithUpdate($expr, true);

@ -298,17 +298,6 @@ trait StdContainerTrait
return $this->isStdArrayExpr($expr) || $this->getStdContainerInfo($expr) !== null;
}
protected function fillStdArray(Expr\StaticCall $expr): string
{
if (!$this->isVarExpr($expr->args[0]->value) or !$this->isStdArray($this->parseIdentifier($expr->args[0]->value))) {
$this->fatalError($expr, 'fill() only support std::array');
}
$array = $this->parseIdentifier($expr->args[0]->value);
$info = $this->context->stdArrays[$array];
$value = $this->convertStdValueExpr($info, $expr->args[1]->value);
return "{$array}_ref.fill({$value})";
}
protected function getStdArrayInfo(Expr\ArrayDimFetch $expr): ?array
{
$tmp = $expr->var;
@ -736,11 +725,6 @@ trait StdContainerTrait
return ['type' => Type::OBJECT, 'class' => $class];
}
protected function parseStdValueType(NodeAbstract $expr, string $owner): string
{
return $this->parseStdValueTypeInfo($expr, $owner)['type'];
}
protected function parseStdClassValueType(Expr\ClassConstFetch $expr, string $owner): string
{
$class = $this->parseIdentifier($expr->class);

@ -594,99 +594,6 @@ trait UniversalMethodCall
return $kwExt ? $kwExt['return_type'] : null;
}
protected function buildInternalExtensionMethod(string $type, string $funcName): ?array
{
$ref = Reflection::getFunction($funcName);
if ($ref === null) {
return null;
}
$totalParams = $ref->getNumberOfParameters();
if ($totalParams < 1) {
return null;
}
if (!$this->validateInternalExtensionFirstParam($type, $funcName)) {
return null;
}
$phpType = Reflection::getFunctionReturnType($funcName);
$returnType = $phpType ? ($this->zendTypeMap[$phpType] ?? Type::VAR) : Type::VAR;
$requiredParams = $ref->getNumberOfRequiredParameters();
$minArgs = max(0, $requiredParams - 1);
$maxArgs = max(0, $totalParams - 1);
if ($totalParams > 0) {
$lastParam = Reflection::getFunctionParameter($funcName, $totalParams - 1);
if ($lastParam !== null && $lastParam->isVariadic()) {
$maxArgs = -1;
}
}
return [
'handler' => 'php_fn',
'fn' => $funcName,
'receiver_pos' => 1,
'return_type' => $returnType,
'min_args' => $minArgs,
'max_args' => $maxArgs,
];
}
protected function validateExtensionFirstParam(string $type, \TypePhp\Entity\FunctionDef $funcDef): bool
{
if (empty($funcDef->argInfoList)) {
return false;
}
$firstParam = $funcDef->argInfoList[0];
// Stream/Box are PHP pseudo-types; their params may be typed or untyped
if ($type === Type::STREAM || $type === Type::BOX) {
return $firstParam->byRef || $firstParam->type === Type::VAR || $firstParam->type === Type::REF || $firstParam->type === $type;
}
if ($firstParam->byRef) {
return $type === Type::ARRAY;
}
$paramType = $firstParam->type;
if ($paramType === Type::VAR) {
return false;
}
return $paramType === $type;
}
protected function validateInternalExtensionFirstParam(string $type, string $funcName): bool
{
$param = Reflection::getFunctionParameter($funcName, 0);
if ($param === null) {
return false;
}
// Stream pseudo-type: accept untyped or by-reference first params
if ($type === Type::STREAM) {
return true;
}
if ($param->isPassedByReference()) {
return $type === Type::ARRAY;
}
$paramType = $param->getType();
if ($paramType === null) {
return false;
}
if ($paramType instanceof \ReflectionNamedType) {
$phpName = $paramType->getName();
$compilerType = $this->zendTypeMap[$phpName] ?? null;
return $compilerType === $type;
}
return false;
}
protected function resolveExtensionFunctionName(string $funcName): ?string
{
if ($this->hasFunction($funcName)) {
return $funcName;
}
return null;
}
/**
* @param string $receiver C++ expression for the receiver
* @param bool $isVar Whether the receiver is a variable (allows mutating methods)

@ -455,7 +455,13 @@ class Preprocessor extends CompilerBase
return $name;
}
protected function findSymbolUsing(NodeAbstract $ast)
/**
* Collect per-file symbol dependencies for the incremental compilation cache.
*
* The cache does not consume this graph yet, but this collector is retained
* intentionally so cache invalidation can later be based on symbol usage.
*/
protected function findSymbolUsing(NodeAbstract $ast): void
{
$nodeFinder = new NodeFinder();
$functionCalls = $nodeFinder->findInstanceOf($ast, Node\Expr\FuncCall::class);
@ -485,8 +491,7 @@ class Preprocessor extends CompilerBase
}
}
// 依赖去重
$depClasses = array_unique($this->symbolCallInFile[$this->file]);
$this->symbolCallInFile[$this->file] = $depClasses;
$this->symbolCallInFile[$this->file] = array_unique($this->symbolCallInFile[$this->file]);
}
protected function prepareNamespace(Node\Stmt\Namespace_ $node): void

@ -74,14 +74,12 @@ class Translator extends Preprocessor
private ?ProjectYamlLoader $projectYamlLoader = null;
private ?NativeBuilder $nativeBuilder = null;
protected bool $verbose = false;
protected array $phpSrcFiles = [];
protected array $ignorePaths = [];
protected array $argInfoHeaderFiles = [];
protected array $registerSymbols = [];
// Windows 资源文件配置(图标、版本信息等)
protected array $resourceConfig = [];
protected bool $useRegisterSymbolsFn = false;
protected array $globalHeaders = [
'cstring',
'phpx.h',
@ -548,7 +546,6 @@ class Translator extends Preprocessor
} else {
$this->save($cppCode, $cppFile);
}
$this->phpSrcFiles[] = $file;
// 生成 stub 文件,依赖 convert 阶段的 use 等信息
$this->genStubFile($this->file);
return $cppCode === '' ? null : $cppFile;
@ -2944,7 +2941,7 @@ CODE;
$needsAttributeSymbols = str_contains($headerCode, 'zend_add_function_attribute(')
|| str_contains($headerCode, 'zend_add_parameter_attribute(')
|| str_contains($headerCode, 'zend_add_global_constant_attribute(');
if ($this->useRegisterSymbolsFn || $needsAttributeSymbols) {
if ($needsAttributeSymbols) {
if (preg_match('/\bstatic\s+void\s+(register_[A-Za-z0-9_]+_symbols)\s*\(\s*int\s+module_number\s*\)/', $headerCode, $matches)) {
$registerSymbolFn = $matches[1];
$this->registerSymbols[] = $registerSymbolFn;
@ -3637,10 +3634,10 @@ CODE;
$rawVar = 'raw_' . $var;
$cppCode .= $this->getIndent() . Type::VAR . ' ' . $rawVar . ' = php::getCallArg(i);' . PHP_EOL;
$cppCode .= $this->genStrictScalarParamCheck($argInfo, $rawVar, $displayName, 'i + 1');
$cppCode .= $this->getIndent() . $var . '.append('
$cppCode .= $this->getIndent() . $var . '.appendValue('
. $this->convertExprFromType($argInfo->type, $rawVar) . ');' . PHP_EOL;
} else {
$cppCode .= $this->getIndent() . $var . '.append(php::getCallArg(i));' . PHP_EOL;
$cppCode .= $this->getIndent() . $var . '.appendValue(php::getCallArg(i));' . PHP_EOL;
}
$this->indentLevel--;
$cppCode .= $this->getIndent() . '}' . PHP_EOL;
@ -3775,19 +3772,6 @@ CODE;
return $cppCode;
}
protected function getClassRegisterCeFunc(ClassDef|InterfaceDef $classDef): string
{
$cppCode = '';
$name = $classDef->getNamespacedName();
$argsDef = $this->getRegisterClassFunctionArgDef($classDef);
$param = $this->getRegisterClassFunctionArgs($classDef);
$cppCode .= 'zend_class_entry *' . $this->getRegisterClassFunction($name) . '(' . $argsDef . ') {' . PHP_EOL;
$cppCode .= $this->getIndent() . 'return register_class_' . $name . '(' . $param . ');' . PHP_EOL;
$cppCode .= '}' . PHP_EOL . PHP_EOL;
return $cppCode;
}
protected function genClassWrapper(ClassDef|InterfaceDef $classDef): string
{
$cppCode = '';
@ -3822,59 +3806,6 @@ CODE;
return $cppCode;
}
/**
* @param array<ConstantDef> $list
*/
protected function genClassConstantList(array $list): string
{
$code = '';
foreach ($list as $const) {
$code .= $this->getIndent() . $this->genClassConstant($const);
}
return $code;
}
protected function genClassConstant(ConstantDef $const): string
{
return 'static const ' . $const->type . ' ' . $const->name . ';' . PHP_EOL;
}
/**
* @param array<PropertyDef> $list
*/
protected function genClassPropertyList(array $list): string
{
$code = '';
foreach ($list as $prop) {
$code .= $this->getIndent() . $this->genClassProperty($prop);
}
return $code;
}
protected function genClassProperty(PropertyDef $prop): string
{
$code = $prop->type . ' ' . $prop->name;
if ($prop->default !== null) {
$code .= ' = ' . $prop->default;
}
return $code . ';' . PHP_EOL;
}
protected function genFunction(string $name, string $returnType, array $args = [], array $lines = []): string
{
$_args = [];
foreach ($args as $arg => $type) {
$_args[] = $type . ' ' . $arg;
}
$code = $returnType . ' ' . $name . '(' . implode(', ', $_args) . ') {' . PHP_EOL;
$code .= implode(PHP_EOL, $lines) . PHP_EOL;
$code .= '}' . PHP_EOL;
return $code;
}
/**
* Build type-check descriptor array from UnionType or NullableType AST node.
* Returns ['check' => array, 'typeStr' => string] or empty check array if no check needed.
@ -5239,87 +5170,4 @@ CODE;
);
}
private function genClassNative(): string
{
$code = 'class ' . $this->class . ' { ';
$publicMethods = [];
$protectedMethods = [];
$privateMethods = [];
$publicConstants = [];
$protectedConstants = [];
$privateConstants = [];
$publicProperties = [];
$protectedProperties = [];
$privateProperties = [];
foreach ($this->classDef->constants as $const) {
if ($const->flags & Modifiers::PUBLIC) {
$publicConstants[] = $const;
}
if ($const->flags & Modifiers::PROTECTED) {
$protectedConstants[] = $const;
}
if ($const->flags & Modifiers::PRIVATE) {
$privateConstants[] = $const;
}
}
foreach ($this->classDef->methods as $method) {
if ($method->flags & Modifiers::PUBLIC) {
$publicMethods[] = $method;
}
if ($method->flags & Modifiers::PROTECTED) {
$protectedMethods[] = $method;
}
if ($method->flags & Modifiers::PRIVATE) {
$privateMethods[] = $method;
}
}
foreach ($this->classDef->properties as $property) {
if ($property->flags & Modifiers::PUBLIC) {
$publicProperties[] = $property;
}
if ($property->flags & Modifiers::PROTECTED) {
$protectedProperties[] = $property;
}
if ($property->flags & Modifiers::PRIVATE) {
$privateProperties[] = $property;
}
}
if ($privateConstants) {
$code .= 'private:' . PHP_EOL;
$code .= $this->genClassConstantList($privateConstants);
}
if ($protectedConstants) {
$code .= 'protected:' . PHP_EOL;
$code .= $this->genClassConstantList($protectedConstants);
}
if ($publicConstants) {
$code .= 'public:' . PHP_EOL;
$code .= $this->genClassConstantList($publicConstants);
}
if ($privateProperties) {
$code .= 'private:' . PHP_EOL;
$code .= $this->genClassPropertyList($privateProperties);
}
if ($protectedProperties) {
$code .= 'protected:' . PHP_EOL;
$code .= $this->genClassPropertyList($protectedProperties);
}
if ($publicProperties) {
$code .= 'public:' . PHP_EOL;
$code .= $this->genClassPropertyList($publicProperties);
}
$code .= '};' . PHP_EOL . PHP_EOL;
return $code;
}
}

@ -2827,7 +2827,7 @@ class ConstInfo extends VariableLike
// Condition will be added by generateCodeWithConditions()
if ($this->name instanceof ClassConstName) {
$code = $this->getClassConstDeclaration($value, $allConstInfos);
$code = $this->getClassConstDeclaration($value);
} else {
$code = $this->getGlobalConstDeclaration($value);
}
@ -2888,12 +2888,10 @@ class ConstInfo extends VariableLike
throw new Exception("Unimplemented constant type: " . $value->type->name);
}
/** @param array<string, ConstInfo> $allConstInfos */
private function getClassConstDeclaration(EvaluatedValue $value, array $allConstInfos): string
private function getClassConstDeclaration(EvaluatedValue $value): string
{
$constName = $this->name->getDeclarationName();
// TODO $allConstInfos is unused
$zvalCode = $value->initializeZval("const_{$constName}_value");
$code = "\n" . $zvalCode;

Loading…
Cancel
Save