We have a multi-tenanted PHP application. This application provides a set of core functionality, and then on a per tenant basis we can build web applications, leveraging and extending the core.
From time to time we make changes that require us to revisit some of the customisations and bring them into line with the core. A recent change was to require that a particular method must return an array. This is easy to indicate in the core, e.g.:
class MyLibrary {
public function myMethod(): array {
...
}
}
However, we would then need to ensure that all the classes that extend the library also have a matching method signature. We will do this, but then also we need to ensure that all of those methods do actually return an array. There are currently about 250 tenants that need checked, and there may be multiple files that extend the library as per the above example.
This led me to think about looking for these methods that don't return an array programatically and I came across this gem.
https://github.com/nikic/php-ast
It would appear that I can use it to read the source for a class, and then look at the syntax tree to see if the myMethod() is returning a value. The particular thing I'm looking for are methods that simply don't return anything.
I tried this as a starting point:
use PhpParser\ParserFactory;
use PhpParser\{Node, NodeTraverser, NodeVisitorAbstract};
$code = file_get_contents('path/to/file.php');
$parser = (new ParserFactory())->createForNewestSupportedVersion();
$ast = $parser->parse($code);
$traverser = new NodeTraverser;
$traverser->addVisitor(new class extends NodeVisitorAbstract {
public function leaveNode(Node $node) {
dump($node);
readline();
echo "\n\n\n\n";
}
});
And this allows me to traverse the AST and see the nodes, and I can see PhpParser\Node\Stmt\ClassMethod
objects, and can see the statements (stmts
) inside it, but I can't quite figure out how to check whether there is a PhpParser\Node\Stmt\Return
in the statements or not.
The documentation on the php-ast library is not detailed enough to help me understand how to do this. Any guidance appreciated.
I asked ChatGPT for advice on this and after initially suggesting a solution using regular expressions, I then asked it to refine the answer using nikic/php-parser
and with a little tweaking I got a working response.
I can't post the result on Stack Overflow as it's against the site policy https://stackoverflow.com/help/gen-ai-policy but the short version of this is:
Node\Stmt\ClassMethod
nodesNode\Stmt\Return_
node then add it to a listHere's the working code: https://gist.github.com/gurubobnz/2ae85e5010158896789e75f3ea375803
There will be an issue here in that there is no execution guarantee of the return, e.g. if (false) { return []; }
will still be considered a return, but it is good enough for me to make a start on my corpus of source files.