From 28de6c86a497960466c303a6f04ae66fd6e7ca49 Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Tue, 7 Apr 2026 18:20:47 +0800 Subject: [PATCH] =?UTF-8?q?fix(php):=20=E8=A7=A3=E5=86=B3=E5=8A=A8?= =?UTF-8?q?=E6=80=81=E8=B0=83=E7=94=A8=E5=92=8C=E6=96=B9=E6=B3=95=E9=87=8D?= =?UTF-8?q?=E5=86=99=E7=9A=84=E7=9B=B8=E5=85=B3=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加了动态调用时的作用域切换代码生成 - 修复了 MethodCall 中的动态调用检测逻辑,区分魔法方法调用 - 为类方法定义添加了 hasDynamicCall 属性标识 - 实现了类继承链中私有方法重写的错误检查 - 添加了多个测试用例验证字符串连接性能和动态调用行为 --- src/Php/CompilerBase.php | 16 ++++++++-- src/Php/Entity/MethodDef.php | 1 + src/Php/Translator.php | 17 +++++++++++ tests/zend/concat/bug40809.phpt | 32 ++++++++++++++++++++ tests/zend/concat/bug44069.phpt | 21 ++++++++++++++ tests/zend/dynamic_call/bug46246.phpt | 42 +++++++++++++++++++++++++++ 6 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 tests/zend/concat/bug40809.phpt create mode 100644 tests/zend/concat/bug44069.phpt create mode 100644 tests/zend/dynamic_call/bug46246.phpt diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index 8d7444e3..2b74ef00 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -923,6 +923,12 @@ class CompilerBase extends \PhpAot\Core\Translator } $this->indentLevel--; $code .= $this->genDebugInfo(); + + // 函数中存在动态调用的函数,需要在运行时动态切换作用域 + if ($this->methodDef and $this->methodDef->hasDynamicCall) { + $code .= $this->genScopeSwitchCode(); + } + $code .= $stmts; $code .= "}\n"; @@ -3856,7 +3862,7 @@ class CompilerBase extends \PhpAot\Core\Translator } } - $dynamicCall = false; + $magicMethod = false; $method = $this->identifierToStr($expr->name, literal: true); // 可转为原生调用的 MethodCall @@ -3873,7 +3879,7 @@ class CompilerBase extends \PhpAot\Core\Translator } } } catch (DynamicCall) { - $dynamicCall = true; + $magicMethod = true; } } @@ -3883,12 +3889,16 @@ class CompilerBase extends \PhpAot\Core\Translator $funcName = ''; } - if ($class and $funcName and !$dynamicCall) { + if ($class and $funcName and !$magicMethod) { $methodPtr = $this->getMethodPtr($class, $funcName); } else { $methodPtr = $method; } + if ($object === 'this_' or $object === 'self' or $object === 'static') { + $this->methodDef->hasDynamicCall = true; + } + if (empty($expr->args)) { return $object . '.call(' . $methodPtr . ')'; } diff --git a/src/Php/Entity/MethodDef.php b/src/Php/Entity/MethodDef.php index e2cfabcd..050f85f9 100644 --- a/src/Php/Entity/MethodDef.php +++ b/src/Php/Entity/MethodDef.php @@ -13,6 +13,7 @@ class MethodDef public int $flags; public string $name; public ?FunctionDef $functionDef = null; + public bool $hasDynamicCall = false; public function __construct(int $flags, string $name) { diff --git a/src/Php/Translator.php b/src/Php/Translator.php index 8186b106..12fb9717 100644 --- a/src/Php/Translator.php +++ b/src/Php/Translator.php @@ -1179,6 +1179,23 @@ class Translator extends Preprocessor $this->method = $name; $flags = $this->parseModifiers($v->flags); + $classDef = $this->classDef; + while (true) { + $extends = $classDef->extends; + if (!$extends) { + break; + } + $classDef = $this->getClass($extends); + if ($classDef->hasMethod($this->method)) { + $methodDef = $classDef->getMethod($this->method); + if ($methodDef->flags & Modifiers::PRIVATE) { + $this->fatalError($v, + 'Cannot override private method `' . + $classDef->getNamespacedName(false) . '::' . $this->method . '()`'); + } + } + } + if (!($flags & Modifiers::ABSTRACT)) { $this->methodDef = new MethodDef($flags, $name); $methodCodes[$name] = $this->parseFunction($v); diff --git a/tests/zend/concat/bug40809.phpt b/tests/zend/concat/bug40809.phpt new file mode 100644 index 00000000..f0ba1d97 --- /dev/null +++ b/tests/zend/concat/bug40809.phpt @@ -0,0 +1,32 @@ +--TEST-- +Bug #40809 (Poor performance of ".=") +--FILE-- + +--EXPECT-- +ok diff --git a/tests/zend/concat/bug44069.phpt b/tests/zend/concat/bug44069.phpt new file mode 100644 index 00000000..b18e16b2 --- /dev/null +++ b/tests/zend/concat/bug44069.phpt @@ -0,0 +1,21 @@ +--TEST-- +Bug #44069 (Huge memory usage with concatenation using . instead of .=) +--FILE-- + +--EXPECT-- +ok diff --git a/tests/zend/dynamic_call/bug46246.phpt b/tests/zend/dynamic_call/bug46246.phpt new file mode 100644 index 00000000..86769f11 --- /dev/null +++ b/tests/zend/dynamic_call/bug46246.phpt @@ -0,0 +1,42 @@ +--TEST-- +Bug #46246 (difference between call_user_func(array($this, $method)) and $this->$method()) +--FILE-- +Test(); + $this->$method(); + call_user_func(array($this, $method)); + } +} + +class B extends A +{ + protected function Test() + { + echo 'Overridden hello from '.get_class($this)."\n"; + } +} + +function main() { + $a = new A; + $b = new B; + + $a->call('Test'); + $b->call('Test'); +} +?> +--EXPECT-- +Hello from A +Hello from A +Hello from A +Overridden hello from B +Overridden hello from B +Overridden hello from B