When preparing an application for a CakePHP 5 upgrade, one useful step is to increase the PHPStan level before starting the full migration. The goal is not only to make the static analysis stricter, but to make hidden problems visible earlier. Many legacy applications still work correctly in production, but they may have unclear types, missing return values, unsafe array access, or methods that are harder to understand. These issues can make the upgrade slower because they appear while changing the framework code.
Increasing the PHPStan level helps the team clean the codebase in a controlled way. Instead of finding many errors during the CakePHP 5 upgrade, the team can fix part of the technical debt before the migration starts. This gives developers more confidence when changing models, services, controllers, commands, and tests. It also helps identify places where the code depends on assumptions that are not clear, like a value always being present, a method always returning an entity, or a variable having a specific type.
In one project that was getting ready for the upgrade, we followed this approach step by step. In the main branch, the PHPStan level was increased from level 1 to level 5 and a baseline was added, so no real fixes were applied directly in main. This allowed the stricter level to be introduced without blocking the branch or forcing a large refactor all at once.
The real fixes were applied in the develop branch. As the team fixed the PHPStan issues, the baseline was updated progressively until it was empty. This made the process much easier to manage because the team could improve the codebase gradually, keep the main branch stable, and still move toward a cleaner application. By the time the CakePHP 5 upgrade starts, the code is already more predictable, easier to refactor, and less risky to change.
Starting from zero: adding PHPStan to the project
If the project is not using PHPStan yet, the first step is to install it as a development dependency:
composer require --dev phpstan/phpstan
Then run PHPStan for the first time with a low level, for example level 1:
vendor/bin/phpstan analyse src/ tests/ --level=1
After confirming that PHPStan runs correctly, create a basic phpstan.neon file at the root:
parameters:
level: 1
paths:
- src
- tests
Then the analysis can be executed using the configuration file:
vendor/bin/phpstan analyse --configuration phpstan.neon
Adding CakePHP-specific PHPStan support
PHPStan is very useful on its own, but a CakePHP application has framework conventions that generic static analysis does not always understand. For example, CakePHP uses table classes, entities, associations, behaviors, components, helpers, mailers, and ORM methods that depend a lot on naming conventions and runtime resolution. For that reason, it is useful to include the CakeDC PHPStan extension for CakePHP. The cakedc/cakephp-phpstan package provides services and rules to improve PHPStan analysis in CakePHP applications, including better type resolution for CakePHP-specific patterns such as tables, helpers, behaviors, and ORM return types.
To install it, run:
composer require --dev cakedc/cakephp-phpstan
If the project uses phpstan/extension-installer, the extension should be loaded automatically. If not, include it manually in the project’s phpstan.neon file:
includes:
- vendor/cakedc/cakephp-phpstan/extension.neon
parameters:
level: 1
paths:
- src
- tests
This extension helps PHPStan understand common CakePHP methods better, for example fetchTable(), loadComponent(), Table::get(), newEntity(), patchEntity(), save(), and other ORM-related methods. It also includes CakePHP-specific rules, such as checking associations, behaviors, components, mailers, debug functions, and entity access patterns.
This is important during an upgrade preparation process because we want PHPStan to report issues that are actually useful for a CakePHP application. The goal is not only to increase the level, but to make the analysis understand the framework better. That gives the team better feedback and reduces the noise that can happen when a static analysis tool does not fully understand the application conventions.
Increasing the level before the upgrade
Once PHPStan is running, the next step is to increase the level. PHPStan supports different rule levels, where lower levels are easier to adopt and higher levels apply stricter checks. A good approach is to increase the level progressively instead of trying to fix everything at once.
In our case, the project was already using PHPStan at level 1, and we wanted to move to level 5 before starting the CakePHP 5 upgrade. The configuration was updated like this:
parameters:
level: 5
paths:
- src
- tests
Then PHPStan can be executed again:
vendor/bin/phpstan analyse --configuration phpstan.neon
At this point, it is normal to see many errors, especially if the project is older or has not been analyzed with stricter rules before. Instead of fixing all of them immediately in the main branch, we generated a baseline.
Creating the PHPStan baseline
A baseline stores the current PHPStan errors, so the team can increase the level without having to fix every existing issue at the same time. This is very useful when working with an existing codebase, because it allows the team to prevent new issues while fixing old ones gradually.
To generate the baseline:
vendor/bin/phpstan analyse --configuration phpstan.neon --generate-baseline
By default, PHPStan creates a file called phpstan-baseline.neon. If you want to explicitly define the filename, you can do it like this:
vendor/bin/phpstan analyse --configuration phpstan.neon --generate-baseline phpstan-baseline.neon
After generating the baseline, include it in the PHPStan configuration:
includes:
- phpstan-baseline.neon
parameters:
level: 5
paths:
- src
- tests
With this in place, the main branch can run PHPStan at level 5 without failing because of the existing known issues. New code should still be checked against the stricter level, and the baseline should not grow with new problems.
Reducing the baseline progressively
After the baseline is created, the real cleanup can happen in a working branch, like develop. Developers can start fixing the reported issues by area: models, controllers, services, commands, or tests. Each time a group of issues is fixed, the baseline can be regenerated or updated until it becomes smaller.
The final goal is to remove the baseline completely. This means the project can pass PHPStan at the higher level without ignoring old errors. For a CakePHP 5 upgrade, this is a strong signal that the codebase is in a better state before starting the framework migration.
This approach does not replace tests or manual review, but it makes the upgrade safer. PHPStan helps detect problems before runtime, and the baseline gives the team a practical way to adopt stricter rules without stopping all development. For long-running CakePHP applications, this can be a very good preparation step before moving to CakePHP 5.
Need help with this in your own CakePHP app?
Talk to a CakePHP expert