Running static analysis on your code saves time by uncovering hidden issues. PHPStan is a static analysis tool for PHP that helps you increase the quality of your codebase. Here’s how to run PHPStan within your GitLab CI pipelines.

It’s good to run PHPStan regularly while you’re building out new features. Using it locally only takes you so far though. You’re reliant on your other team members being as disciplined as you are. Integrating static analysis into a CI/CD workflow ensures code can’t be merged if it would break your project’s main branch.

Getting Setup with PHPStan

You first need to add PHPStan into your project. We’ve already got a detailed guide on installing and configuring PHPStan, so we’ll only cover the basics here.

First, use Composer to install PHPStan:

Next, create a basic phpstan.neon configuration file in your project:

The temporary directory is overridden to assist GitLab CI’s caching, setup below.

You can now run PHPStan locally to check your configuration works:

At this stage, it doesn’t matter whether the tests pass.

Configuring GitLab for CI

Make sure you’ve pushed your code to a project on your GitLab server. You’ll need to check the Pipelines feature is enabled for your project – if you see “CI / CD” in the left sidebar, you’re good to go.

To enable your project’s CI system, click the “Settings” button in the sidebar. Expand the “Visibility, project features, permissions” section and enable the “Pipelines” feature.

If you use GitLab’s Merge Requests (MRs) in a disciplined manner, you can now configure GitLab to prevent MRs from getting merged unless they have a successful pipeline. Expand the “Merge requests” settings section and check the “Pipelines must succeed” toggle button. Click “Save” to confirm. This will stop you accidentally merging an MR when PHPStan fails against its changes.

To use GitLab CI, you’ll need to have a GitLab Runner defined at the instance, group or project level. Runners are responsible for executing the CI jobs created by the GitLab system.

We’re going to use the PHPStan Docker image to run PHPStan in our CI pipeline. This requires the use of a GitLab Runner using the Docker executor. If you’re on a self-managed instance and need to configure a new Runner, follow the guidance in our article on setting up GitLab CI.

Creating a GitLab CI Pipeline

GitLab CI is configured using a .gitlab-ci.yml file at the root of your project. CI pipelines support multiple sequential stages. Each stage’s jobs run in parallel. For our purposes of running PHPStan, we need a single stage which runs one job.

This GitLab CI file contains all we need to run PHPStan within our pipeline. We define a stage, phpstan, containing a job that’s also called phpstan. The job uses the official PHPStan Docker image from the GitHub container registry.

The GitLab CI cache is configured to cache the .tmp and vendor directories. This will improve the performance of subsequent runs on the same branch. The cache will get restored automatically. Back in our phpstan.neon, we set the tmpDir to .tmp for this reason – it means we can now confidently reference it in the CI pipeline’s caching configuration.

We also cache vendor to avoid needlessly reinstalling Composer dependencies on each run. Note that you don’t need to run composer install manually – the official PHPStan Docker image invokes it automatically.

The –error-format flag is passed to PHPStan’s analyse command. This configures PHPStan to create a JSON file in the format accepted by GitLab’s code quality report. Down in the artifacts section, this file gets uploaded to GitLab after the job completes.

Using the Pipeline

Commit your .gitlab-ci.yml and push to your GitLab server. The CI system should now kick in and create your first pipeline. Use the “CI / CD” link in the left navigation to view the pipeline’s progress.

If you get a green tick, PHPStan’s tests passed! Your branch is in a good state and it’s ready to merge. If a red cross appears, you’ve got more work to do. PHPStan and GitLab CI just stopped you merging potentially broken code.

You can get the list of errors by clicking the download icon to the right of the pipeline. Select the PHPStan code quality artifact to obtain the JSON report of errors which PHPStan found.

Using with Merge Requests

Reading the JSON manually doesn’t make for a great experience. However, GitLab’s Merge Requests expose the contents of the report automatically. Because the report is tagged as a GitLab code quality artifact, GitLab knows how to present the information within.

Merge requests with a failing pipeline should display an expandable “Code quality” section. This indicates the number of errors encountered. Expand the section to view a complete list of problems found by PHPStan.

Once you’ve addressed the issues, push your changes up to GitLab. The pipeline will run again. Once it’s completed, you’ll see the new status on the Pipelines screen and in your merge request’s code quality widget.

Conclusion

PHPStan helps you write better PHP that’s less susceptible to hidden problems. To get the most from it, the tool must be incorporated into your development workflow in such a way that it can’t be ignored or circumvented.

Using PHPStan with GitLab CI gives you the consistency you need to be confident in your code. Configuring GitLab to block MRs with a failed pipeline means changes can’t enter your main branch without passing a PHPStan run. PHPStan’s full support for GitLab’s code quality reports make it easy to assess errors without leaving the web UI, helping you rapidly fix any problems which are uncovered.