PHPStan#
How PHPStan Works#
- AST (Abstract Syntax Tree): PHPStan analyzes code by converting it into a syntax tree, enabling consistent interpretation regardless of formatting.
-
Custom Rules:
- Rules implement the
\PHPStan\Rules\Ruleinterface. - Methods:
getNodeType(): Specifies the type of node to analyze (e.g., method calls, new instances).processNode(): Contains logic for identifying and reporting errors.
- Rules implement the
Custom rules#
Objective#
The goal is to enhance knowledge sharing by integrating company-specific standards and solutions directly into the codebase using PHPStan custom rules. This helps bridge the gap between documentation and practice, ensuring that crucial conventions and lessons are not forgotten during development.
Why Use PHPStan for Knowledge Sharing?
Traditional documentation requires developers to actively search for information, which may be overlooked or forgotten. PHPStan custom rules embed this knowledge directly into the development process by providing real-time feedback during static code analysis.
- Bug Prevention:
- Automate solutions for known issues, preventing repeated developer effort.
- Enforce Standards:
- Ensure compliance with company conventions (e.g., avoiding certain ORM practices).
- Promotes team-wide adherence to standards.
- Reduces reliance on developers’ memory or manual checks.
- Streamlines onboarding and knowledge transfer.
- Production Safety:
- Flag hard-to-reproduce bugs (e.g., incorrect event subscriber usage).
Action to Take When Adding a New Rule#
When adding a new PHPStan custom rule, it’s essential to prevent errors from legacy code from being flagged. This is where the baseline feature of PHPStan comes into play.
What is a Baseline?
A baseline is a snapshot of all errors currently present in your codebase. PHPStan uses this to ignore existing issues while still detecting new ones in updated or added code. This allows teams to adopt stricter rules without immediately needing to fix historical errors, making the transition smoother.
Steps to Add a Rule Without Affecting Legacy Code
- Reset the Baseline:
- Use the script
run-stan-reset-baselinedefined in the project’scomposer.jsonfile. - This will generate a new baseline file that includes all currently detectable errors, including those triggered by the newly added rule.
- Use the script
- Commit the Updated Baseline File:
- After generating the new baseline, commit it to your repository. This ensures the baseline is shared with your team and reflects the latest set of ignored issues.
- Validate the Changes:
- Run PHPStan locally and in your CI pipeline to confirm that no new or unexpected errors are being reported.
By maintaining and updating the baseline, you can progressively enforce new standards without overwhelming the team with legacy issues. This approach allows for continuous improvement in code quality while keeping development workflows manageable.
Steps to Create a Custom Rule
-
Define the Rule:
- Extend
\PHPStan\Rules\Ruleand bind the rule to a specific node type. - Use
RuleErrorBuilder::message()to define error messages. -
Example: A rule to disallow
var_dump():public function processNode(Node $node, Scope $scope): array { if ($node->name->toString() === 'var_dump') { return [RuleErrorBuilder::message('var_dump is not allowed')->build()]; } return []; }
- Extend
-
Test the Rule:
- Extend
PHPStan\Testing\RuleTestCaseand implementgetRule()to return the custom rule instance. - Write test cases with code templates and expected errors.
- Example: Detect
var_dump()in a test file and confirm error reporting.
- Extend
- Run PHPStan:
- Use
phpstan analyseto validate the implementation.
- Use
For more detailed examples, refer to the sample implementations in PHPStan's documentation on rules.
Custom Rules included within WP Rocket#
- Discourage the use of
apply_filtersin favour ofwpm_apply_filters_typed - Discourage the use of
update_optionin favour ofOptionobject, with theset()method. - Ensuring that no hooks are called within ORM
- Make sure that the callback set within
get_subscribed_eventsfrom aSubscriberis a method that exists.