Skip to main content

Tighten up your Drupal code using PHPStan

Published on

This past weekend was at Florida Drupal Camp, and I gave a talk about using PHPStan to tighten up your Drupal codebase. For the past two years, the Drupal community has been leveraging PHPStan indirectly through drupal-check and Upgrade Status to find usages of deprecated code as we journeyed from Drupal 8 to Drupal 9. This is barely the tip of the iceberg of what value PHPStan provides, but it had an immense impact.

You can download the slides as a PDF. The session was also recorded and will be available on the camp's YouTube channel later.

I wanted to write a blog to touch on items not covered in the slides but as speaker notes and audio from the recording.

Catch me (virtually) at SFDUG in March

I'll be presenting this same talk virtually at the San Fransisco Drupal Users Group meetup on March 10th. I will be updating my slides based on feedback and discussions from my talk at FLDC.

A quick history lesson on drupal-check

Part of this is my fault. The phpstan/extension-installer package did not exist. Setting up PHPStan + phpstan-drupal wasn't difficult, but you had to make sure to include the extension configuration files in your phpstan.neon for phpstan-drupal and phpstan-deprecation-rules. Something like this:

    level: 0
    - vendor/phpstan/phpstan-deprecation-rules/rules.neon
    - vendor/mglaman/phpstan-drupal/extension.neon

It's not the end of the world. But it leaves room for mistakes. Dries suggested we provide something more straightforward for the end-users, hence the birth of drupal-check and its demo during the DrupalCon Seattle Driesnote.

The benefits of PHPStan

Two main takeaways could be taken away from my session, I believe:

  1. Running PHPStan at level 0 is not enough, and we all should be running at level 2 for catching deprecations
  2. You should add PHPStan as part of your development workflow to help your team leads and junior developers

Why do we need to run PHPStan at level 2?

Level 2 begins to report undefined methods called on classes. The slides go through the example of a typo for a call to an expected isPublished method in a hook_node_insert hook. PHPStan does not report the typo until we go to level 2. When the typo is fixed, assuming that is the problem, PHPStan may say that it still does not exist. This is because the hook has the default type of EntityInterface when it should be NodeInterface, which has isPublished.

This example is based on real support that I have provided multiple times. One of those was handled in GitHub issues versus Slack/Twitter. You can see it here:

Helping junior developers grow by using PHPStan

Start using PHPStan as part of your development flow. It needs to be part of your continuous integration process. It needs to run at least at level 5. I'm not going to explain in depth what rules 1-5 provide. You can see that in the documentation for PHPStan:

It will provide peace of mind for your team leads doing code reviews. It reduces the cognitive load of checking for minor details. I mean, your PHPUnit tests should catch that anyways. Right? Because you do have PHPUnit tests. Right? It also provides an emotional disconnect from team leads requesting changes to the code. Instead of a junior having to push code, wait for a review, receive various request changes, and then get frustrated that their senior pair or team lead is "too picky," you can point to the tool.

It also solves delays in teams distributed across multiple timezones. Your pull or merge request isn't "ready" until it passes PHPStan, PHPCS, and PHPUnit. You know the code is pretty solid by that point. That allows the reviewer to focus on what matters in the code being delivered.

I have overlooked very basic bugs because of review fatigue. If you have four different pull requests in your queue, you will miss basic things. So let's automate the easy stuff.