From 02e16794b828fe5fd016650cb2053f44a7508eac Mon Sep 17 00:00:00 2001 From: Yurun Date: Mon, 13 Jul 2026 16:52:40 +0800 Subject: [PATCH] =?UTF-8?q?fix(compiler):=20=E4=BF=AE=E5=A4=8D=E9=9D=99?= =?UTF-8?q?=E6=80=81=E6=96=B9=E6=B3=95=E8=B0=83=E7=94=A8=E6=8C=89=E5=BC=95?= =?UTF-8?q?=E7=94=A8=E5=8F=82=E6=95=B0=E4=BC=A0=E5=80=BC=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Parser/MethodCallTrait.php | 16 ++++++-- .../static/static-call-byref-arg.phpt | 38 +++++++++++++++++++ 2 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 tests/compiler/static/static-call-byref-arg.phpt diff --git a/src/Parser/MethodCallTrait.php b/src/Parser/MethodCallTrait.php index adf60e11..6d4fb329 100644 --- a/src/Parser/MethodCallTrait.php +++ b/src/Parser/MethodCallTrait.php @@ -252,6 +252,7 @@ trait MethodCallTrait $this->guardAbstractMethod($parentClass, $method, $expr); $methodPtr = $this->getMethodPtr($parentClass, $method); } else { + $method = ''; // parent:: is bound to the lexical parent class, not the runtime // object's parent. Look the method up on that class, then invoke it // through this_ so Zend receives the current call scope. @@ -261,7 +262,8 @@ trait MethodCallTrait if (empty($expr->args)) { return 'this_.call(' . $methodPtr . ')'; } - return 'this_.call(' . $methodPtr . ', ' . $this->parseCallArgs($expr->args) . ')'; + // 传入方法名与父类名,以便在按引用参数检测时解析方法签名 + return 'this_.call(' . $methodPtr . ', ' . $this->parseCallArgs($expr->args, $method, $parentClass) . ')'; } @@ -453,6 +455,8 @@ trait MethodCallTrait { $self = false; $callScope = []; + $rtFunc = ''; + $rtClass = ''; $class = $this->parseIdentifier($expr->class); // parent::$method() still has a lexical parent class even when the @@ -475,13 +479,17 @@ trait MethodCallTrait } $placeHolder = $fn; } elseif ($this->isNameExpr($expr->class) and $class === 'static') { + $method = $this->parseIdentifier($expr->name); $methodPtr = $this->identifierToStr($expr->name, literal: true); $fn = Symbol::getCalledCe() . ', php::getMethod(' . Symbol::getCalledCe() . ', ' . $methodPtr . ')'; $this->context->beforeStmtLines[] = $this->formatCppLineComment( 'Static Method Call: ', - 'static::' . $this->parseIdentifier($expr->name) . '()' + 'static::' . $method . '()' ); $placeHolder = $this->genArray([Symbol::getCalledClass(), $methodPtr]); + // 用于在按引用参数检测时解析方法签名(late static binding 在当前类层级中解析) + $rtFunc = $method; + $rtClass = $this->getNamespacedClassName($this->class); } elseif ($this->isNameExpr($expr->class)) { if ($class === 'self') { $class = $this->class; @@ -493,6 +501,8 @@ trait MethodCallTrait _do_call: $method = $this->parseIdentifier($expr->name); + $rtFunc = $method; + $rtClass = $class; $dynamicCall = false; $this->context->beforeStmtLines[] = $this->formatCppLineComment( 'Static Method Call: ', @@ -556,7 +566,7 @@ trait MethodCallTrait return $call . '(' . $fn . ')'; } try { - return $this->genRuntimeFunctionCall($fn, $expr->args); + return $this->genRuntimeFunctionCall($fn, $expr->args, $rtFunc, $rtClass); } catch (PlaceHolder) { return $this->genPlaceHolder($placeHolder); } diff --git a/tests/compiler/static/static-call-byref-arg.phpt b/tests/compiler/static/static-call-byref-arg.phpt new file mode 100644 index 00000000..e0a975f4 --- /dev/null +++ b/tests/compiler/static/static-call-byref-arg.phpt @@ -0,0 +1,38 @@ +--TEST-- +Static method calls (self / static / class name / parent) with by-reference args +--FILE-- + +--EXPECT-- +string(4) "test" +string(4) "test" +string(4) "test" +string(4) "test"