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