The PHP parser task will run static code analyses on your PHP code. You can specify which code visitors should run on your code or write your own code visitor.
Composer
composer require --dev nikic/php-parser
Config
The task lives under the php_parser
namespace and has following configurable parameters:
# grumphp.yml
grumphp:
tasks:
phpparser:
ignore_patterns: []
php_version: null
visitors: {}
triggered_by: [php]
ignore_patterns
Default: []
This is a list of patterns that will be ignored by the PHP Parser. With this option you can skip files like tests. Leave this option blank to run analysis for every php file.
php_version
Default: null
Can be any PHP version specified as major.minor
. For example: 8.2
.
There is a special placeholder latest
, which will use the latest supported PHP version from php-parser.
If left empty, the system's PHP version will be picked. This is the default behaviour.
visitors
Default: {}
Use this parameter to specify what code you want to scan. This is made possible by node visitors following PHP_Parser syntax. Without any visitors specified, PHP Parser will only check code syntax (similar to php lint). In the next chapter, you can find a list of built-in visitors. It's also possible to write your own visitor!
triggered_by
Default: [php]
This option will specify which file extensions will trigger the php blacklist task. By default, php blacklist will be triggered by altering a php file. You can overwrite this option to whatever filetype you want to validate!
- declare_strict_types
- forbidden_class_method_calls
- forbidden_function_calls
- forbidden_static_method_calls
- nameresolver
- never_use_else
- no_exit_statements
This visitor can be used to enforce declare(strict_types=1)
in every PHP file.
# grumphp.yml
grumphp:
tasks:
phpparser:
visitors:
declare_strict_types: ~
This visitor is not configurable!
This visitor can be used to look for forbidden class method calls.
# grumphp.yml
grumphp:
tasks:
phpparser:
visitors:
forbidden_class_method_calls:
blacklist:
- '$dumper->dump'
blacklist
Default: []
This is a list of blacklisted class method calls. The syntax is $variableName->methodName
.
When one of the functions inside this list is being called by your code,
the parser will mark this method as an error.
This visitor can be used to look for forbidden function calls.
# grumphp.yml
grumphp:
tasks:
phpparser:
visitors:
forbidden_function_calls:
blacklist:
- 'var_dump'
blacklist
Default: []
This is a list of blacklisted function calls. When one of the functions inside this list is being called by your code, the parser will mark this method as an error.
Note that statements like die()
and exit
are not functions but exit nodes. You can validate these statements by adding the no_exit_statements
visitor to your configuration.
This visitor can be used to look for forbidden static method calls.
# grumphp.yml
grumphp:
tasks:
phpparser:
visitors:
forbidden_static_method_calls:
blacklist:
- 'Dumper::dump'
blacklist
Default: []
This is a list of blacklisted static method calls. The syntax is Fully\Qualified\ClassName::staticMethodName
.
When one of the functions inside this list is being called by your code,
the parser will mark this method as an error.
This visitor is an alias for the built-in PhpParser NameResolver visitor. It looks for class aliases in your code and adds the alias as an attribute to the class nodes.
Note: This visitor is enabled by default since it is used by other visitors. You don't have to register it in the task configuration.
This visitor is not configurable!
This visitor will search for the else
and elseif
keywords in your code.
An error will be added if one of those statements is found.
More information about Object Calisthenics can be found
here
and
here.
# grumphp.yml
grumphp:
tasks:
phpparser:
visitors:
never_use_else: ~
This visitor is not configurable!
This visitor will search for exit statements like die()
or exit
in your code.
An error will be added if an exit statement is found.
# grumphp.yml
grumphp:
tasks:
phpparser:
visitors:
no_exit_statements: ~
This visitor is not configurable!
Creating your own visitor is easy!
Just create a class that implements the PhpParser\NodeVisitor
interface:
// PhpParser\NodeVisitor
interface NodeVisitor
{
public function beforeTraverse(array $nodes);
public function enterNode(Node $node);
public function leaveNode(Node $node);
public function afterTraverse(array $nodes);
}
Once you've written your visitor, you'll have to register it to the service container:
services:
grumphp.parser.php.visitor.your_visitor:
class: 'Your\Visitor\Class'
arguments: []
tags:
- {name: 'php_parser.visitor', alias: 'your_visitor'}
Since we use the service container, you are able to inject the dependencies you need with the arguments
attribute.
The php_parser.visitor
tag will make your class available in GrumPHP.
Tha alias your_visitor
can now be set as a visitor in the phpparser task:
# grumphp.yml
grumphp:
tasks:
phpparser:
visitors:
your_visitor: ~
An important note on the visitors is that they are completely stateless! If you've already written a PhpParser Visitor before, you know that advanced visitors will contain a specific state about the class. When scanning the next file, the state needs to be reset.
In our implementation, we've chosen to always create a new visitor for every file. This way, you don't have to think about clearing the state of a visitor on each run. This will result in easy and understandable visitors!
We also added some optional interfaces and to make it easier to interact with the GrumPHP context:
ConfigurableVisitorInterface
The ConfigurableVisitorInterface
allows you to make the visitor configurable in the grumphp.yml
file.
To make sure the visitor works as you please, It is recommended to use the OptionsResolver
to validate the configured options.
// GrumPHP\Parser\Php\Visitor\ConfigurableVisitorInterface;
interface ConfigurableVisitorInterface extends NodeVisitor
{
public function configure(array $options);
}
ContextAwareVisitorInterface
The ContextAwareVisitorInterface
will make your task aware of the context the visitor is running in.
The ParserContext
object will have access to the file information and the errors collection.
This last one can be used to add a new error in your visitor.
// GrumPHP\Parser\Php\Visitor\ContextAwareVisitorInterface
interface ContextAwareVisitorInterface extends NodeVisitor
{
public function setContext(ParserContext $context);
}
AbstractVisitor
In the built-in visitors, we use the AbstractVisitor
that extends the PhpParser\NodeVisitorAbstract
.
This means that you only have to implement the methods from the NodeVisitor
that you need.
It also implements the ContextAwareVisitorInterface
and provides an easy method for logging errors in your custom visitor.
The blueprint of this abstract visitor looks like this:
// GrumPHP\Parser\Php\Visitor\AbstractVisitor;
class AbstractVisitor extends NodeVisitorAbstract implements ContextAwareVisitorInterface
{
protected $context;
public function setContext(ParserContext $context);
protected function addError($message, $line = -1, $type = ParseError::TYPE_ERROR);
}