# The Case for Strict PHPStan Baselines in Enterprise Codebases


Modernizing a legacy PHP application presents a paradox: you critically need strict static analysis to prevent future bugs, but turning on a tool like PHPStan immediately throws 5,000 errors, completely breaking the CI pipeline.



During a recent stabilization project on an enterprise platform (`rlh-core`), we faced exactly this. The codebase had excellent business logic but was rife with missing return types, empty variable checks (`empty($message)` rather than strict `null` checks), and loosely defined arrays.

## The Impossible Migration

The naive approach is to halt feature development for a month and force the team to fix all 5,000 errors until PHPStan returns green. From a business perspective, this is financial suicide.

The alternative is to leave PHPStan disabled, allowing the technical debt to accumulate.

## The "Baseline" Deployment Strategy

To enforce future quality while respecting past debt, we implemented the PHPStan Baseline pattern. 

### 1. Generating the Debt Ledger
We configured PHPStan to its maximum strictness (Level 8) and ran it against the entire codebase. When it identified the 5,000 errors, we piped that output into a specialized baseline file (`phpstan-baseline.neon`).

This baseline acts as a cryptographic signature of the *existing* technical debt. Essentially, it tells the CI pipeline: "Ignore these specific 5,000 errors on these specific 5,000 lines of code."

### 2. Enforcing the Border
Once the baseline was committed, the CI pipeline immediately went "green." However, the strict Level 8 rules were now fully active for all *new* code. 

If a developer wrote a new class that lacked a return type, or attempted to access an array key without verifying its existence, PHPStan failed the build. They could not introduce new debt.

### 3. Incremental Eradication
We introduced a rule regarding the baseline: if you touch a file to add a feature, you must resolve the baseline errors for that file. 

When an engineer fixed an `empty()` check on a legacy controller, PHPStan automatically noticed the error no longer existed and requested that the specific error be removed from the baseline file (`reportUnmatched: true`).

## A Culture of Gradual Perfection

Over a six-month period, the baseline shrank from 5,000 errors to under 300, without a single dedicated "refactoring sprint." The application became highly deterministic and type-safe simply by enforcing a strict boundary on new code. 

When dealing with enterprise technical debt, the strategy isn't to burn the house down; it's to stop adding fuel to the fire.

***
*Need an Enterprise CMS Architect to modernize your legacy PHP platforms? View my case studies at [victorjimenezdev.github.io](https://victorjimenezdev.github.io) or connect with me on LinkedIn.*


---
*Need an Enterprise Drupal or WordPress Architect to rescue your project or lead your migration? Let's talk. View my case studies at [victorjimenezdev.github.io](https://victorjimenezdev.github.io) or connect with me on LinkedIn.*

*Originally published at [VictorStack AI — Drupal & WordPress Reference](https://victorstack-ai.github.io/agent-blog/strict-phpstan-baselines-enterprise-codebases/)*
