Proxy copies default values of inherited methods as written: class names resolve against the child file's imports
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
調査の方向性
Read src/Proxy/Generator/ParameterGenerator.php and AbstractInterceptedPropertyGenerator.php, then inspect AttributeGroupsGenerator::$argumentCloner and ResolvedNameQualifyingVisitor for the existing name-qualification pattern. Add coverage for inherited defaults from another file, including colliding imports, self::CONST, and promoted or intercepted properties; run the listed composer checks with opcache.jit=disable. Done means the parent defaults are preserved and existing proxy snapshots remain unchanged.
索引モデルが issue の本文から書いたものです。
説明
Found during #826 (the fix went out with that declined change, see PR #831). Reproduced on master dc64ef7.
Problem
When a woven class gets an intercepted method from a parent class (or a trait) declared in another file, the proxy re-declares that method. ParameterGenerator builds the parameter type from the resolved AST names, which is correct and fully qualified. The default value, however, is copied as written (ValueGenerator::fromExprNode($astParam->default), src/Proxy/Generator/ParameterGenerator.php).
The proxy lives in the child's file and carries the child's use imports. A short class name in an inherited default (Level::LEVEL, Foo::class, new Foo()) therefore resolves against the child's imports, not the parent's.
Reproduction
// ImportedDefaultsBase.php
namespace Go\Instrument\Transformer\Stubs;
use Go\Stubs\Collision\The as Level;
class ImportedDefaultsBase
{
public function log(string $level = Level::LEVEL, ?Level $target = null): string { return $level; }
}
// ImportedDefaultsChild.php
namespace Go\Instrument\Transformer\Stubs;
use Go\Stubs\Collision\Interceptor as Level; // same short name, another class
class ImportedDefaultsChild extends ImportedDefaultsBase { /* … */ }
With a before advice on ImportedDefaultsChild->log, the generated proxy of the child contains:
use Go\Stubs\Collision\Interceptor as Level;
…
public function log(string $level = Level::LEVEL, ?\Go\Stubs\Collision\The $target = null): string
The type is right (\Go\Stubs\Collision\The), but the default now means Go\Stubs\Collision\Interceptor::LEVEL. Both stubs happen to define LEVEL = 'debug', which hides it in the test fixtures.
In real code, depending on the classes involved, the intercepted method then:
- silently gets a different default (another class's constant);
- fails on the call with "Undefined constant";
- fails with "Class not found" when the child file has no such import.
All of this happens only when the argument is omitted, so the bug is easy to miss.
Scope
- Affected: default values of parameters, and of promoted and intercepted properties (
AbstractInterceptedPropertyGeneratorcopies the AST default the same way), declared in a parent class or trait from another file. - Not affected: types, which are already qualified from
resolvedName, and attribute arguments, whichAttributeGroupsGeneratoralready clones and qualifies withResolvedNameQualifyingVisitor. - Unaffected case: members declared in the woven file itself, because the proxy shares that file's imports.
- Related edge case:
self::CONSTin an inherited default refers to the declaring class in PHP. In the re-declared proxy method,selfis the proxy (child) class, which matters when the child overrides the constant.
Proposed decision for the implementing agent
Keep it small and in line with how master already treats types and attribute arguments. Do not reintroduce the declined #826 alias machinery.
- When copying a default AST node (parameters, promoted properties, intercepted properties), clone it and qualify its names with the existing
ResolvedNameQualifyingVisitor(same traverser pattern asAttributeGroupsGenerator::$argumentCloner). Do this only when the member's declaring file differs from the file being woven. Compare the declaring class'sgetFileName()with the woven file, which also covers trait members. Proxies of a class's own members stay byte-identical, so no existing snapshot changes. - In the same foreign-file case, replace
selfin the default with the declaring class name (rooted). This preserves PHP's meaning of an inheritedself::CONST.staticcan't appear in a constant expression, andparentshould resolve to the declaring class's parent. - Make sure the qualifying visitor does not turn
self/parentinto\self/\parent. A fix for that was part of the reverted #826; re-apply it if needed.
Acceptance
- A new stub pair (the reproduction above, with different constant values in the two colliding classes). The child's proxy emits
\Go\Stubs\Collision\The::LEVEL, and a functional or unit test callinglog()without arguments gets the parent's value. - A case with
self::CONSTin an inherited default, with the child overriding the constant: the parent's value is kept. - Promoted/intercepted property defaults from a parent in another file are covered.
- Existing proxy snapshots under
tests/Instrument/Transformer/_filesare unchanged (own-file members are untouched). composer test,composer analyze,composer cs, andcomposer test:performance:transformation(generator change). Run withopcache.jit=disable: the PHP 8.5.12 tracing-JIT bug breaks the functional subprocess tests.
Scoring
| Score | Why | |
|---|---|---|
| Effort | Low | One reused visitor on the default-copy path of the parameter and property generators, a declaring-file check, plus stubs and tests. |
| Impact | Medium | It needs an inherited, intercepted method with a class-referencing default and a colliding short name across files, so it is rare. When it hits, it is a silent wrong value or a call-time fatal. |
- 主要言語
- PHP
- スター
- 1.7k
- フォーク
- 166
- 平均マージ
- 23時間 58分
- マージ済み PR(30日)
- 40
環境構築
このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
goaop/framework のほかの issue
-
Enhancement
難易度 3/5 1〜2日 初心者へのやさしさ 72/100
メンテナーはふだん 1 日以内に返信
-
cache:warmup:opcache runs out of memory with the default memory_limit (128M) on larger applicationsオープンBug
難易度 4/5 3〜5日 初心者へのやさしさ 55/100
メンテナーはふだん 1 日以内に返信
-
Bug To Be Discussed
難易度 5/5 1週間以上 初心者へのやさしさ 28/100
メンテナーはふだん 1 日以内に返信
-
Bug
難易度 4/5 3〜5日 初心者へのやさしさ 45/100
メンテナーはふだん 1 日以内に返信
-
Enhancement Performance
難易度 4/5 3〜5日 初心者へのやさしさ 48/100
メンテナーはふだん 1 日以内に返信
goaop/framework の issue をすべて見る
似ている issue
-
I forgot the add database cross reference button対応中かも @dsenalik が今日担当しました。 オープンGood First Issue Group 2 - Data Storage | Tripal DBX | Chado Group 7 - Page Display
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
-
enhancement good first issue
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
SutariyaVishal/parallel-branches#15 ·
メンテナーはふだん 1 日以内に返信
-
Modules list cache misses every hour because it is keyed on the hourly accounts token対応中かも @SachaFARINEL が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
PrestaShopCorp/ps_mbo#899 ·
-
enhancement priority Sales
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
novalo-dev/Prestashop-MCP-Server#201 ·
メンテナーはふだん 1 日以内に返信
-
enhancement
難易度 2/5 1〜3時間 初心者へのやさしさ 74/100
web-token/jwt-framework#757 ·
メンテナーはふだん 1 日以内に返信