Skip to content

Do not report a private method overriding a private trait method as unused - #6191

Open
Jean-Beru wants to merge 1 commit into
phpstan:2.2.xfrom
Jean-Beru:fix-12201-private-method-overriding-trait
Open

Do not report a private method overriding a private trait method as unused#6191
Jean-Beru wants to merge 1 commit into
phpstan:2.2.xfrom
Jean-Beru:fix-12201-private-method-overriding-trait

Conversation

@Jean-Beru

Copy link
Copy Markdown

Fixes phpstan/phpstan#12201

Why

A class member takes precedence over the member of the same name coming from a used trait. So a private method redeclared in the class is the one the trait's own methods call.

UnusedPrivateMethodRule sees those call sites only when the trait is part of the analysed files. In a project whose paths exclude its dependencies, ClassMethodsNode::getMethodCalls() collects no call at all. The class method is then reported as unused.

The canonical case is a Symfony application. The recipe generates a Kernel that redeclares KernelTrait::getAllowedEnvs(), and the trait lives in vendor/.

// vendor/symfony/dependency-injection/Kernel/KernelTrait.php, not analysed
trait KernelTrait
{
	private function getAllowedEnvs(): array
	{
		return [];
	}

	protected function getKernelParameters(): array
	{
		// ...
		if (!$knownEnvs = array_flip($this->getAllowedEnvs())) {
		// ...
	}
}
// src/Kernel.php, analysed
class Kernel extends BaseKernel
{
	use MicroKernelTrait; // uses KernelTrait

	/**
	 * @return list<string>
	 */
	private function getAllowedEnvs(): array // reported as unused
	{
		return ['prod', 'dev', 'test'];
	}
}

Every new Symfony 8.1 project hits this from level 4 up. ignoreErrors is the only way out.

What

A private method is skipped when a used trait declares a private method of the same name.

getTraits() is enough without recursion. PHP flattens trait composition. getAllowedEnvs() comes from the nested KernelTrait, and the reflection of MicroKernelTrait already reports it.

…nused

A class member takes precedence over the member of the same name coming
from a used trait, so a private method redeclared in the class is what the
trait's own methods call. The rule sees those call sites only when the
trait is part of the analysed files: analysing a project whose paths do not
include its dependencies leaves ClassMethodsNode::getMethodCalls() with no
call at all, and the class method is reported as unused.

The canonical case is a Symfony application, where the framework recipe
generates a Kernel redeclaring KernelTrait::getAllowedEnvs() while the
trait lives in vendor/, outside of the analysed paths.

Skip those methods. Nothing is left to distinguish an override that the
trait calls from one it does not, so a redeclared private method the trait
never calls is no longer reported either.

Fixes phpstan/phpstan#12201

Assisted-by: Claude Code:claude-opus-5
@Jean-Beru Jean-Beru changed the title Do not report a private method overriding a private trait method as u… Do not report a private method overriding a private trait method as unused Aug 6, 2026
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.

"method unused" when overriding private methode of a trait

1 participant