Repository navigation
Report inheritance cycles with a rule instead of a reflection error - #6712
SanderMuller wants to merge 1 commit into
Conversation
A class that extends itself, interfaces that extend each other and traits that use each other cannot be declared in PHP. A class on a parent class cycle now has no parent instead of throwing CircularReference, and a trait inside a trait on a cycle processes only the traits reflection says it uses. CircularInheritanceRule reports the cycle on each of its members, at level 0. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
20c7a3c to
05e9f43
Compare
|
when did the phpstan-laravel and the tempest-framework CI check broke? I saw them failling also in others PRs but did not yet saw the root-cause PR (unrelated to this PR - just asking) |
|
did you verify the results of newly added tests in this PR against the state we had before 613b1b1 ? |
calebdw/phpstan-laravel#50 is the reason for phpstan-laravel I think |
Yes. I analysed the PR's cycle fixtures one file at a time, at level 8, on three trees:
So each cycle that was reported before 613b1b1 is reported again, now as a rule error with a line. |
BetterReflection 6.73.0.6 (ondrejmirtes/BetterReflection#47) no longer throws
CircularReferencefor an inheritance cycle. A class-like on a cycle has no supertypes of its kind instead. Since 613b1b1, 2.3.x therefore reports nothing for such a cycle. This is the phpstan-src part of the change, with a rule that reports the cycle.The changes:
CircularInheritanceRule, at level 0, reports the cycle on each of its members. The identifiers areclass.circularExtends,interface.circularExtendsandtraitUse.circular, and the error cannot be ignored. Examples:Class Foo extends itself.andClass Foo extends Bar, which extends Foo.ClassReflection::getParentClass()returnsnullfor a class that extends itself, instead of throwingCircularReference. A class that extends a class on a cycle keeps that parent.TraitUseHandlerprocesses only the traits that reflection says the trait uses. A trait on a trait cycle uses none.ClassReflection.cppandTraitUseHandler.cppget the same changes.The
TraitUseHandlerchange also fixes a crash on 2.3.x. Take a class that uses a trait on a cycle, where the members of one trait use the members of the other one. Analysing it stops with an internal error,MissingPropertyFromReflectionException. The newAnalyserIntegrationTest::testTraitCycleMembers()covers this case. A trait on a cycle uses no traits, so the class gets the members of the first trait only. The test therefore also expectsAccess to an undefined property.#6729 removed the part of the
result-cache-parse-errore2e step that expected a reflection error for a class that extends itself. The newresult-cache-circular-inheritancestep checks instead that the result cache is saved when the rule reports a cycle.Verification:
CircularInheritanceRuleTestcovers:testTraitCycleMembers()fails on 2.3.x with the internal error.result-cache-circular-inheritancebreaks a class cycle and closes a trait cycle between two runs, and checks that the cached errors follow. It also checks that the first run saves the result cache.make testspasses with and without the Turbo extension (22,636 tests, 74 skipped).make phpstan, phpcs andmake lintreport no errors.smoke.phpreports ALL OK, andside-by-side.php,signature-parity.phpandwalk-trace.phppass. On the rule's fixtures and the cycle fixtures ofAnalyserIntegrationTest, the raw output is identical with the extension loaded and not loaded.Performance on wordpress-develop at level 9, cold runs from source without Turbo, on an M4 Pro. Base is
cb3b7e994. Each value is the median of 3 alternating rounds, with the range in brackets. The output is identical, because wordpress-develop has no inheritance cycles.🤖 Generated with Claude Code