From f803a0fd4100840dd10a67514f4206f1edaf417c Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Tue, 9 Jun 2026 12:53:10 +0800 Subject: [PATCH] =?UTF-8?q?refactor(Php):=20=E4=BC=98=E5=8C=96=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E9=87=8D=E5=86=99=E6=A3=80=E6=B5=8B=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E4=BB=A5=E6=94=AF=E6=8C=81=E5=AD=90=E7=B1=BB=E9=A2=84=E5=A4=84?= =?UTF-8?q?=E7=90=86=E9=A1=BA=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 提取 fullMethodName 的小写转换为独立变量 - 添加对子类是否已覆盖方法的检查机制 - 实现递归检查所有子类及其后代子类的同名方法定义 - 更新父类方法重写标记逻辑以支持动态调用处理 - 添加完整的文档注释说明新的方法重写检测功能 --- src/Php/Preprocessor.php | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/Php/Preprocessor.php b/src/Php/Preprocessor.php index 65ee706c..7da54de0 100644 --- a/src/Php/Preprocessor.php +++ b/src/Php/Preprocessor.php @@ -605,14 +605,17 @@ class Preprocessor extends CompilerBase $fullClassName = $this->getFullClassName(); $fullMethodName = $fullClassName . '::' . $this->method; - $this->classMethodOverride[strtolower($fullMethodName)] = false; - // 查找父类是否有同名方法,递归查找 + $fullMethodNameLower = strtolower($fullMethodName); $fullClassNameLower = strtolower($fullClassName); + // 检查子类是否已覆盖此方法(子类先于父类被预处理的情况) + $isOverridden = $this->isMethodOverriddenInSubClasses($fullClassNameLower, $this->method); + $this->classMethodOverride[$fullMethodNameLower] = $isOverridden; + + // 查找父类是否有同名方法,递归向上标记父类方法已被覆盖 while (isset($this->classExtends[$fullClassNameLower])) { $parentClass = $this->classExtends[$fullClassNameLower]; $parentMethodLower = strtolower($parentClass . '::' . $this->method); - // 父类有同名方法,子类覆盖了父类方法,这种情况不能直接使用 C++ 函数,而是使用 ZendVM 动态调用 if (isset($this->classMethodOverride[$parentMethodLower])) { $this->classMethodOverride[$parentMethodLower] = true; } @@ -622,6 +625,30 @@ class Preprocessor extends CompilerBase $this->resetMethod(); } + /** + * 递归检查所有子类(及子类的子类)是否已定义了同名方法,用于处理子类先于父类被预处理的情况。 + */ + private function isMethodOverriddenInSubClasses(string $classNameLower, string $method): bool + { + if (!isset($this->classSubClasses[$classNameLower])) { + return false; + } + $stack = $this->classSubClasses[$classNameLower]; + while (!empty($stack)) { + $subClass = array_shift($stack); + $subMethodLower = $subClass . '::' . strtolower($method); + if (isset($this->classMethodOverride[$subMethodLower])) { + return true; + } + if (isset($this->classSubClasses[$subClass])) { + foreach ($this->classSubClasses[$subClass] as $grandChild) { + $stack[] = $grandChild; + } + } + } + return false; + } + protected function parseInterface(Node\Stmt\Interface_ $v): void { $name = $this->parseIdentifier($v->name);