Analyse a project with PHPStan
grim-core ships PHPStan, its configuration and the baseline the monorepo keeps. A project runs the same analysis with one overlay, phpstan-instance.neon, and has to run it where the application boots, which is the app container.
Before you start
The stack is up (grim up), and the project is on core 1.3.25 or later. From that release grim-core carries three files next to composer.json:
phpstan.neon |
the monorepo's configuration: level, paths, Larastan |
phpstan-baseline.neon |
findings the monorepo grandfathers, every module's |
phpstan-instance.neon |
phpstan.neon with unmatched baseline entries allowed |
The baseline names files of every module in the monorepo. Your project installs a few of them, so most entries match nothing, and plain phpstan.neon stops on the first "is neither a directory, nor a file path". phpstan-instance.neon is the same configuration with that check switched off. Always analyse through it.
The ritual, in order
Three steps. The first is the whole analysis; the other two are about reading it and trusting it next time.
Run it in the app container
Larastan boots the application to learn what
app('…')returns, what a model's columns are and which config keys exist. The application boots only where its.envpoints, and that is the stack: on your machineredisandmysqlare hostnames of nothing, and the analysis dies with "Laravel framework bootstrap failed".grim composerruns in the app container, and core'scomposer.jsonhas ananalysescript. Everything after the second--goes to PHPStan:$ grim composer -- analyse -- -c phpstan-instance.neon --no-progress … 101 Access to an undefined property Modules\Users\Models\User::$planning_role. … [ERROR] Found 4 errorsThe first
--ends grim's options, the second ends Composer's. Without the second one Composer swallows-cand PHPStan reads plainphpstan.neon.A whole project takes about a minute. To look at one module, name it:
$ grim composer -- analyse -- -c phpstan-instance.neon --no-progress src/Registry [OK] No errorsTell your finding from an inherited one
A finding in a file you changed is yours: fix it before you push.
A finding in a module you did not touch usually comes from what the project installs. The monorepo has every module enabled and every migration run; your project does not. The common case is a core model reading a column a module you do not install adds:
src/Users/Models/User.php:101 Access to an undefined property Modules\Users\Models\User::$planning_role.Larastan learns the columns from the migrations on disk.
planning_roleis added by the Planning module, which this project does not install. That is a question for whoever maintains the module the finding is in (does it really need a column another module adds?), not something to fix in your project. Report it to them with the line PHPStan printed.Keep the cache honest
PHPStan caches results in
var/phpstanper file. A file that did not change keeps its old result even when what it depends on did, so aftergrim update, or after enabling or removing a module, clear the cache:$ grim composer -- exec phpstan -- clear-result-cache -c phpstan-instance.neon Result cache cleared from directory: /var/www/html/var/phpstanClearing reads the configuration too, so it needs
-c phpstan-instance.neonlike the analysis does.
What you have now
The project analysed with the configuration and baseline of its train, in the environment the application runs in. What is left is either yours or a question for a module's maintainer. The unit check on a pull request runs the same analysis over one module; see Read the unit check on your pull request.
When it does not work
Laravel framework bootstrap failed. The analysis ran outside the container, or the stack is down. Run it through grim composer with the stack up.
is neither a directory, nor a file path, nor a fnmatch pattern, for files of modules you do not have. PHPStan read phpstan.neon, not the overlay. Check the second --.
phpstan-instance.neon does not exist. The project is on core older than 1.3.25. Bring it to 1.3.25 or later with grim update.
The process is killed with no message. The container ran out of memory. The analyse script asks for 4 GB; give Docker more, or analyse one module at a time.
Next recipe
First deploy to a fresh VPS
Take a bare Ubuntu or Debian server and a project that runs on your machine, and end with the project live on its own domain over HTTPS.
Read itSpells used here
grim composer
Run Composer in the container
Run Composer inside the app container, against the PHP version and extensions the app really runs on.
grim shell
Step inside a container
Open an interactive bash session in the app container, or in another service of the local stack.
grim update
Board the newest train
Move core, every module and every theme onto the newest release train grim.json allows, or a single module within the train it is on.
Related recipes
Read the unit check on your pull request
What the single `unit` check on a grim-* pull request does, how to read its annotations, and how to reproduce every one of its steps on your own machine before you push again.
Change a module and send it back
Check what kind of module you are in, make, test and commit the change, read the dry run, open the pull request, and take the release when it arrives.