From f9516c43c98226a4d33cb0d3377feadbdab58dbe Mon Sep 17 00:00:00 2001 From: Yurun Date: Wed, 15 Jul 2026 19:47:04 +0800 Subject: [PATCH] =?UTF-8?q?fix(compiler):=20=E4=BF=AE=E5=A4=8D=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E4=B8=ADself=E8=BF=94=E5=9B=9E=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/CompilerBase.php | 5 ++- .../class/interface-method-self-return.phpt | 42 +++++++++++++++++++ .../interface-self-return-namespaced.phpt | 36 ++++++++++++++++ 3 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 tests/compiler/class/interface-method-self-return.phpt create mode 100644 tests/compiler/namespace/interface-self-return-namespaced.phpt diff --git a/src/CompilerBase.php b/src/CompilerBase.php index 074a1517..fab95bf8 100644 --- a/src/CompilerBase.php +++ b/src/CompilerBase.php @@ -1017,7 +1017,10 @@ class CompilerBase implements PropertyAccessContext protected function getFullClassName(): string { - return ltrim($this->namespace . '\\' . $this->class, '\\'); + // 在接口上下文中,$this->class 为空但 $this->interface 已设置, + // `self` 类型声明应解析为接口自身的完整名称。 + $classLike = $this->class !== '' ? $this->class : $this->interface; + return ltrim($this->namespace . '\\' . $classLike, '\\'); } protected function getFullMethodName(string $fullClassName, string $method): string diff --git a/tests/compiler/class/interface-method-self-return.phpt b/tests/compiler/class/interface-method-self-return.phpt new file mode 100644 index 00000000..90e44eab --- /dev/null +++ b/tests/compiler/class/interface-method-self-return.phpt @@ -0,0 +1,42 @@ +--TEST-- +interface method with `self` return type implemented by class (fluent interface), and namespace block containing comments +--FILE-- +value = $value; + return $this; + } + } + + function main() + { + $test = new TestClass; + // get() returns self, so the result still satisfies the interface + var_dump($test->get() instanceof TestInterface); + var_dump($test === $test->get()); + // fluent chaining of self-returning methods + var_dump($test->get()->setValue(42)->value); + } +} +?> +--EXPECT-- +bool(true) +bool(true) +int(42) diff --git a/tests/compiler/namespace/interface-self-return-namespaced.phpt b/tests/compiler/namespace/interface-self-return-namespaced.phpt new file mode 100644 index 00000000..cfda0bad --- /dev/null +++ b/tests/compiler/namespace/interface-self-return-namespaced.phpt @@ -0,0 +1,36 @@ +--TEST-- +interface method `self` return type resolves to the interface's fully-qualified name inside a named namespace +--FILE-- +log[] = 'chain'; + return $this; + } + } +} + +namespace { + function main() + { + $w = new \App\Widget(); + var_dump($w->chain()->chain() instanceof \App\Chainable); + var_dump(count($w->log)); + } +} +?> +--EXPECT-- +bool(true) +int(2)