Visitar URL original
[2.3.0] False positive method.unusedParameter for a private method passed around as a callable · Issue #15405 · phpstan/phpstan · GitHub
Skip to content

[2.3.0] False positive method.unusedParameter for a private method passed around as a callable #15405

Description

@gnutix

Bug report

With bleeding edge (unusedParameters), PHPStan 2.3.0 reports method.unusedParameter on a private method that is handed out as a callable — through a first-class callable (self::plus(...)) or Closure::fromCallable([self::class, 'minus']). Once the method escapes the class that way, its callers are outside the class and pass every argument, so its signature is a contract like a public method's: here an expression engine calls every registered function as $fn($context, ...$args), and most functions ignore $context.

UnusedMethodParametersRule documents that it only checks private methods because "a private method has no callers outside the class, so its signature is not a contract"; a private method turned into a callable breaks that premise. Closures with the same unused parameter (static fn (string $context, int $a): int => $a) are not reported.

Code snippet that reproduces the problem

<?php declare(strict_types = 1);

final class Operators
{
	/** @return array<string, Closure(string, int, int): int> */
	public static function all(): array
	{
		return [
			'+' => self::plus(...),
			'-' => Closure::fromCallable([self::class, 'minus']),
		];
	}

	private static function plus(string $context, int $a, int $b): int
	{
		return $a + $b;
	}

	private static function minus(string $context, int $a, int $b): int
	{
		return $a - $b;
	}
}

foreach (Operators::all() as $operator) {
	echo $operator('some context', 1, 2);
}

Configuration: level 4 with conf/bleedingEdge.neon included.

repro.php:14  Method Operators::plus() has an unused parameter $context.   [method.unusedParameter]
repro.php:19  Method Operators::minus() has an unused parameter $context.  [method.unusedParameter]

Expected output

No error: a private method referenced as a callable (first-class callable syntax, or a callable array/string naming it) should be treated like a public one by UnusedMethodParametersRule.

Did PHPStan help you today? Did it make you happy in any way?

Yes — 2.3.0's unused-variable detection found real dead code across our codebase, including a test that never checked what it was meant to.

Activity

  1. changed the title [-]False positive method.unusedParameter for a private method passed around as a callable[/-] [+][2.3.0] False positive method.unusedParameter for a private method passed around as a callable[/+] on Oct 6, 2026
  2. mergeable commented on Oct 6, 2026

    @mergeable

    This bug report is missing a link to reproduction at phpstan.org/try.

    It will most likely be closed after manual review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions