# AOT 编译器类继承规则 ## 📋 概述 AOT(Ahead-Of-Time)编译器在编译阶段会对类的继承关系进行严格检查。与传统的 PHP 运行时检查不同,AOT 编译器要求在**编译期**就能确定所有父类和接口的存在性。 --- ## ⚠️ 核心规则 ### 规则一:只能继承已存在的类 ```php // ✅ 正确:继承 PHP 内置类 class MyException extends Exception {} // ✅ 正确:继承同一项目中定义的类 class BaseClass {} class ChildClass extends BaseClass {} // ❌ 错误:继承不存在的类 class MyClass extends NonExistentClass {} // 编译错误:Class `MyClass` inherits from a non-existent class `NonExistentClass` ``` ### 规则二:不能继承 autoload 运行时载入的类 ```php // ❌ 错误:依赖 autoload 的类 class MyClass extends ExternalLibrary\BaseClass {} // 如果 BaseClass 需要通过 autoload 在运行时加载,编译将失败 // ✅ 正确:使用接口代替 interface BaseInterface {} class MyClass implements BaseInterface {} ``` ### 规则三:不能继承内部类(Internal Class) ```php // ❌ 错误:继承 PHP 内部类 class MyArray extends ArrayObject {} // 编译错误:Class `MyArray` Cannot inherit built-in class `ArrayObject` // ✅ 正确:使用组合模式 class MyContainer { private ArrayObject $storage; public function __construct() { $this->storage = new ArrayObject(); } } ``` --- ## 🔍 编译期检查机制 ### 检查流程 1. **词法分析阶段** - 解析 `extends` 和 `implements` 关键字 - 提取父类和接口的名称 2. **符号表构建** - 收集当前文件中所有已定义的类 - 查询 PHP 内置类列表 - 验证继承关系的合法性 3. **错误报告** - 发现非法继承时立即报错 - 提供详细的错误位置和原因 ### 检查代码位置 相关实现在 `src/Php/Translator.php`: ```php if ($extends) { $parentClass = $this->getParentClass($class->extends); if ($this->hasNativeClass($parentClass)) { // 父类是已定义的 native 类 $parent = $this->getClassDef($parentClass); if ($parent->flags & Modifiers::FINAL) { $this->fatalError($class, "Class `{$this->class}` cannot extend final class `{$parentClass}`"); } $this->classDef->extends = $parentClass; } else { // 检查是否为 PHP 内部类 if (Reflection::isInternalClass($parentClass)) { $this->fatalError($class, "Class `{$this->class}` Cannot inherit built-in class `$parentClass`"); } else { $this->fatalError($class, "Class `{$this->class}` inherits from a non-existent class `$parentClass`"); } } } ``` --- ## 🎯 合法继承示例 ### 示例一:继承项目内定义的类 ```php area; } } // 继承基类(✅ 允许) class Circle extends Shape { private float $radius; public function __construct(float $radius) { $this->radius = $radius; } public function calculateArea(): float { $this->area = M_PI * $this->radius ** 2; return $this->area; } } function main() { $circle = new Circle(5); echo "Circle area: " . $circle->getArea() . "\n"; } ``` ### 示例二:实现接口 ```php name = $name; $this->price = $price; } public function render(): string { return "
{$this->name} - \${$this->price}
"; } public function serialize(): string { return json_encode(['name' => $this->name, 'price' => $this->price]); } } function main() { $product = new Product('Widget', 19.99); echo $product->render() . "\n"; echo $product->serialize() . "\n"; } ``` ### 示例三:多层继承 ```php data[$key] = $value; } abstract public function execute(): void; } // 抽象的用户控制器 abstract class UserController extends Controller { protected ?string $userId = null; public function setUserId(string $id): void { $this->userId = $id; } } // 具体的用户列表控制器(✅ 允许) class UserListController extends UserController { private array $users = []; public function execute(): void { echo "User List for ID: {$this->userId}\n"; foreach ($this->users as $user) { echo " - {$user}\n"; } } } function main() { $controller = new UserListController(); $controller->setUserId('123'); $controller->execute(); } ``` --- ## ❌ 非法继承示例 ### 示例一:继承不存在的类 ```php ``` **编译错误**: ``` Fatal error: Class `MyClass` inherits from a non-existent class `NonExistentBase` in /path/to/file.php on line X ``` **解决方案**: ```php ``` **编译错误**: ``` Fatal error: Class `MyService` inherits from a non-existent class `ExternalLib\BaseClass` in /path/to/file.php on line X ``` **解决方案**: **方案 A - 使用接口**: ```php base = new BaseClass(); } public function process(): mixed { return $this->base->doSomething(); } } ``` ### 示例三:继承 PHP 内部类 ```php ``` **编译错误**: ``` Fatal error: Class `MyDatabase` Cannot inherit built-in class `PDO` in /path/to/file.php on line X ``` **解决方案**: ```php connection = new PDO($dsn); } public function query(string $sql): array { return $this->connection->query($sql)->fetchAll(); } } ``` --- ## 💡 最佳实践 ### 1. 优先使用接口而非继承 ```php // ❌ 不推荐:深度继承链 class A {} class B extends A {} class C extends B {} class D extends C {} // ✅ 推荐:使用接口 interface ServiceInterface {} class UserService implements ServiceInterface {} class ProductService implements ServiceInterface {} ``` ### 2. 使用组合代替继承 ```php // ❌ 不推荐:继承内部类 class MyCollection extends ArrayCollection { // ... } // ✅ 推荐:组合模式 class Collection { private ArrayCollection $items; public function __construct() { $this->items = new ArrayCollection(); } public function add(mixed $item): void { $this->items->add($item); } } ``` ### 3. 在项目内定义可继承的基类 ```php middleware('auth'); echo "Handling user request\n"; } } function main() { $controller = new UserController(); $controller->handle(); } ``` ### 4. 避免循环依赖 ```php // ❌ 错误:循环继承会导致编译失败 // file1.php class A extends B {} // file2.php class B extends A {} // ✅ 正确:单向继承 // base.php class Base {} // child.php class Child extends Base {} ``` --- ## 🔧 故障排除 ### 问题一:编译时报 "non-existent class" **症状**: ``` Fatal error: Class `MyClass` inherits from a non-existent class `ParentClass` ``` **诊断步骤**: 1. 检查 `ParentClass` 是否在编译单元中定义 2. 确认没有拼写错误 3. 验证类的命名空间是否正确 **解决方案**: ```php // 确保父类在子类之前定义或在同一文件中 class ParentClass {} class MyClass extends ParentClass {} ``` ### 问题二:无法使用第三方库的类作为父类 **症状**: 需要使用外部库的功能,但不能直接继承 **解决方案**: **方法 A - 适配器模式**: ```php class ExternalAdapter { private ExternalClass $external; public function __construct() { $this->external = new ExternalClass(); } public function doWork(): mixed { return $this->external->execute(); } } ``` **方法 B - 委托模式**: ```php class Wrapper { public function __call(string $name, array $args): mixed { $external = new ExternalClass(); return call_user_func_array([$external, $name], $args); } } ``` ### 问题三:需要扩展 PHP 内置功能 **症状**: 想要增强或修改 PHP 内置类的行为 **解决方案**: **使用装饰器模式**: ```php class EnhancedStorage { private ArrayObject $storage; public function __construct() { $this->storage = new ArrayObject(); } public function set(string $key, mixed $value): void { echo "Setting {$key}\n"; $this->storage[$key] = $value; } public function get(string $key): mixed { echo "Getting {$key}\n"; return $this->storage[$key] ?? null; } } ``` --- ## 📊 对比:AOT vs 传统 PHP | 特性 | AOT 编译器 | 传统 PHP | |------|-----------|----------| | **检查时机** | 编译期 | 运行时 | | **错误发现** | 编译时立即报错 | 执行到代码时才报错 | | **autoload 支持** | ❌ 不支持作为父类 | ✅ 完全支持 | | **继承内部类** | ❌ 禁止 | ✅ 允许(部分) | | **性能影响** | 无运行时开销 | 有运行时检查开销 | --- ## 📚 相关资源 - **类型系统**: [NATIVE_TYPES.md](NATIVE_TYPES.md) - **兼容性限制**: [INCOMPATIBLE_PHP_FEATURES.md](INCOMPATIBLE_PHP_FEATURES.md) - **编译模式**: [COMPILATION_MODES.md](COMPILATION_MODES.md) - **快速入门**: [QUICKSTART.md](QUICKSTART.md) --- ## ❓ 常见问题 ### Q: 为什么 AOT 编译器不允许继承 autoload 类? A: AOT 编译器在编译阶段就需要知道所有类的完整结构。autoload 是在运行时触发的机制,编译期无法获取类的定义信息,因此无法生成正确的 C++ 代码。 ### Q: 如何判断一个类是否是内部类? A: AOT 编译器使用 `Reflection::isInternalClass()` 函数来判断。该函数会扫描所有已声明的类,并使用 `ReflectionClass::isInternal()` 方法检测。 ### Q: 可以实现接口吗? A: ✅ 可以!AOT 编译器完全支持实现接口。接口只定义方法签名,不涉及具体实现,因此可以在编译期验证。 ### Q: trait 可以使用吗? A: Trait 的使用同样受到限制。Trait 必须在编译期可见,不能依赖 autoload 动态加载。 --- **最后更新**: 2024 年 3 月 20 日 **适用版本**: PHP AOT Compiler v1.x