Menu

Parameter Out Type Extensions

When a function or method modifies a by-reference parameter, PHPStan uses the @param-out PHPDoc tag to know the type of the variable after the call. But when the output type depends on the arguments passed to the call, a static PHPDoc is not sufficient.

The implementation is all about applying the core concepts so check out that guide first and then continue here.

This is the interface your extension needs to implement for non-static methods:

namespace PHPStan\Type;

use PhpParser\Node\Expr\MethodCall;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\ParameterReflection;

interface MethodParameterOutTypeExtension
{

	public function isMethodSupported(
		MethodReflection $methodReflection,
		ParameterReflection $parameter,
	): bool;

	public function getParameterOutTypeFromMethodCall(
		MethodReflection $methodReflection,
		MethodCall $methodCall,
		ParameterReflection $parameter,
		Scope $scope,
	): ?Type;

}

The extension has two methods:

  • isMethodSupported() — return true when your extension wants to handle the given method and parameter combination.
  • getParameterOutTypeFromMethodCall() — return the output type of the by-reference parameter, or null to fall back to the default behavior.

Here’s an example for a method that populates a by-reference parameter with a type determined by the first argument:

namespace App\PHPStan;

use PhpParser\Node\Expr\MethodCall;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\ParameterReflection;
use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\IntegerType;
use PHPStan\Type\MethodParameterOutTypeExtension;
use PHPStan\Type\StringType;
use PHPStan\Type\Type;

class CastMethodParameterOutExtension implements MethodParameterOutTypeExtension
{

	public function isMethodSupported(
		MethodReflection $methodReflection,
		ParameterReflection $parameter,
	): bool
	{
		return $methodReflection->getDeclaringClass()->getName() === \App\Caster::class
			&& $methodReflection->getName() === 'cast'
			&& $parameter->getName() === 'value';
	}

	public function getParameterOutTypeFromMethodCall(
		MethodReflection $methodReflection,
		MethodCall $methodCall,
		ParameterReflection $parameter,
		Scope $scope,
	): ?Type
	{
		$args = $methodCall->getArgs();
		if (count($args) < 1) {
			return null;
		}

		$typeArg = $scope->getType($args[0]->value);
		if ($typeArg instanceof ConstantStringType && $typeArg->getValue() === 'int') {
			return new IntegerType();
		}

		return new StringType();
	}

}

With this extension, PHPStan knows the type of the by-reference parameter after the call:

$caster = new Caster();

$caster->cast('int', $value);
\PHPStan\dumpType($value); // int

$caster->cast('string', $value);
\PHPStan\dumpType($value); // string

The implementation needs to be registered in your configuration file:

services:
	-
		class: App\PHPStan\CastMethodParameterOutExtension
		tags:
			- phpstan.methodParameterOutTypeExtension

There’s also analogous functionality for:

Tracking dependencies for the result cache #

Available in PHPStan 2.3.0

If the extension reads something PHPStan doesn’t know about to resolve the type, like a configuration file, typehint the $scope parameter as Scope&DependencyTracker in the PHPDoc and track it with $scope->trackFileDependency() or one of the other DependencyTracker methods. When it changes, the result cache analyses the file with the call again. Learn more »

Theme
A
© 2026 PHPStan s.r.o.