Generic types when requiring a file that returns an anonymous function #13396
-
I build some CLI application where I want to dynamically develop or adjust parts of the business logic – without restarting the command. So I implement small functional bricks as anonymous functions in dedicated files, include these files and execute the function. Simplified the code looks like: Anonymous function in some file that can be modified during runtime of the CLI application: return function (MyType $param1, string $param2): MyReturnType {
return $somethingOfMyReturnType;
}; And on the caller site: $resultOfMyReturnType = $this->executeStep(
'/path/to/my_file.php',
[$parameterOfMyType, $parameterOfStringType],
);
// ...
protected function executeStep(string $stepFile, array $parameters): mixed
{
$stepFunction = require $stepFile;
Assert::isCallable($stepFunction);
return $stepFunction(... $parameters);
} Now I wonder if it is possible to reason about the types in this part of the code: $resultOfMyReturnType = $this->executeStep(
'/path/to/my_file.php',
[$parameterOfMyType, $parameterOfStringType],
); I'm mainly interested in the type of |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
Yes it is, you need to write a dynamic return type extension for Inside the extension you'll have to parse the file contents and invoke NodeScopeResolver by yourself to get the returned ClosureType. Here's a pseudocode that would do that for you: $nodes = $this->parser->parseFile($fileName);
$fileScope = $this->scopeFactory->create(ScopeContext::create($fileName));
$returnType = null;
$nodeScopeResolver->processNodes($nodes, $fileScope, static function (Node $node, Scope $scope) use (&returnType): void {
if ($scope->getFunction() !== null) {
return;
}
if (!$node instanceof Return_ || $node->expr === null) {
return;
}
$returnExprType = $scope->getType($node->expr);
if (!$returnExprType->isCallable()->yes()) {
return;
}
$acceptors = $returnExprType->getCallableParametersAcceptors($scope);
$returnType = TypeCombinator::union(...array_map(fn ($acceptor) => $acceptor->getReturnType(), $acceptors));
});
return $returnType; |
Beta Was this translation helpful? Give feedback.
-
Great, I totally forgot that I could write my own extension. I will give it a try! |
Beta Was this translation helpful? Give feedback.
Yes it is, you need to write a dynamic return type extension for
executeStep
method (https://phpstan.org/developing-extensions/dynamic-return-type-extensions).Inside the extension you'll have to parse the file contents and invoke NodeScopeResolver by yourself to get the returned ClosureType.
Here's a pseudocode that would do that for you: