Skip to content

[symfony] Accept inherited contracts and method attributes in "NoListenerWithoutContractRule" - #334

Merged
TomasVotruba merged 1 commit into
symplify:mainfrom
bmdevel:listener-inherited-contract
Oct 2, 2026
Merged

TomasVotruba merged 1 commit into
symplify:mainfrom
bmdevel:listener-inherited-contract

Conversation

@bmdevel

@bmdevel bmdevel commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

NoListenerWithoutContractRule reports 2 kinds of listener that do have a contract:

1. A contract inherited from a parent class

The rule checks only the implements of the class node itself. A listener that extends a class which implements a listener interface is reported, although it has a contract. An example is a Doctrine 1 record listener:

final class RecordListener extends Doctrine_Record_Listener // implements Doctrine_Record_Listener_Interface
{
}

The rule now also accepts the interfaces from the class reflection, which include the inherited ones.

2. #[AsEventListener] on a method

Symfony registers a listener through the attribute on the class or on a method:

final class ExceptionListener
{
    #[AsEventListener(event: KernelEvents::EXCEPTION)]
    public function onKernelException(ExceptionEvent $event): void
    {
    }
}

The rule read only the class attributes. It now also reads the method attributes.

Each case has a fixture in NoListenerWithoutContractRuleTest. Both were reported before the change. The full suite, ECS, PHPStan and Rector pass.

…enerWithoutContractRule"

A listener that extends a class implementing a listener interface has a
contract, even if the class node itself lists no "implements"; for
example a Doctrine 1 record listener that extends Doctrine_Record_Listener.

Symfony also registers a listener through #[AsEventListener] on a
method, not only on the class.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@TomasVotruba

Copy link
Copy Markdown
Member

LGTM

@TomasVotruba
TomasVotruba merged commit 80787f9 into symplify:main Oct 2, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants