``

Implementing static analysis in Laravel transforms your development workflow from guessing to knowing. Most teams delay setting it up because they fear rewriting their codebase. However, integrating PHPStan and Larastan into an existing application allows you to catch bugs—for example, a mixed return type on a method—without touching production logic. Whether you are maintaining a legacy monolith or a modern API-first app, adding Laravel Pint for style ensures your static analysis is about cleanliness, not arguments.
.
Static analysis in Laravel refers to the practice of running automated tools that check your source code for potential errors without actually executing it. It’s code reading, but smarter.
The trio of tools mentioned here serves three distinct but complementary purposes:
User model, knows how relationships work, and validates that you aren't accessing a nullable property in a way that would crash the application."You should ignore 90% of your static analysis errors initially."
Most developers get scared off by static analysis because they run it at a high strictness level (8 or 9) on a legacy codebase full of missing PHPDoc blocks. They fail their CI pipeline daily, feel discouraged, and disable the tool.
The industry norm is wrong. Start by configuring your CI pipeline to let errors pass (level 0 or level 1). Your CI should just check if the tools are installed and working once a day. Run strict analysis locally only when you are touching that specific file. You can’t refactor what you can’t run. Build the muscle memory of fixing these issues one feature scope at a time.
graph LR
A[IDE / Composer Script] --> B(Static Analysis Engine)
B --> C{Tool Using?}
C -->|Low Level| D[Laravel Pint]
C -->|High Level| E[PHPStan]
E --> F{Is Laravel Context?}
F -->|Yes| G[Larastan Extension]
F -->|No| H[Standard Type Checking]
G --> I[Validates Eloquent Models]
H --> I
C --> J[CI Pipeline]
J --> K[Build Pass/Fail]
When you run a command like vendor/bin/pint or vendor/bin/phpstan analyze, you aren't asking the computer to "guess" your intent. You are querying a logic engine. Laravel Pint uses a configuration file (.php-cs-fixer.php) to define a set of rules. Larastan uses a configuration file (phpstan.neon) to define the strictness level (level 0 to 9).
Developers often struggle with static analysis in Laravel because they rely on functional programming styles array_map or complex closures where the return type is implicit. The engine doesn't know what comes out of a closure.
In real-world usage, this leads to "Magic Numbers" and "Mixed Types."
$item->user->profile, forgetting that user might be null.@var User|null.Implementing Laravel Pint and PHPStan introduces a critical architectural consideration: The Configuration Drift.
If you hardcode strict PSR-12 rules in your editor and level 8 analysis in your config, you create a "Linting Prison." Every junior developer hired will break the build 50 times a day.
The Solution: Environment-Based Configuration.
Store your analysis configuration in phpstan.neon.dist and pint.dist. In your CI workflow (GitHub Actions), use a .github/workflows/ci.yml that reads the environment:
This ensures your developers can ship features fast, but the integrity of the codebase is verified only when it matters.
First, we fix the plumbing. Laravel uses a micro-package strategy for Larastan.
composer require --dev nunomaduro/larastan
Create a file named phpstan.neon in your project root.
parameters:
paths:
- src
- app
- tests
level: 5 # Start higher than 0 but lower than 9 for sanity
checkMissingIterableValueType: false
checkGenericClassInNonGenericObjectType: false
reportUnmatchedIgnoredErrors: false
# Laravel Specifics
bootstrapFiles:
- vendor/nunomaduro/collision/src/phpstan.php
- vendor/laravel/framework/src/Illuminate/Foundation/bootstrap/providers.php
ignoreErrors:
# Ignore generic errors in #[MapProjection] attributes often found in query builders
- '#Parameter \#3 \$value of class ReflectionAttribute::newInstance expects string, int given.#'
Make the commands usable in the terminal.
Run this composer command to add flexibility:
composer config scripts.php-cs-fixer="pint"
composer config scripts.phpstan="phpstan analyse"
Now, you can just run composer phpstan from anywhere. This is better for your team because every machine needs the same version of these tools.
Pint is usually required by default, but let's ensure it's configured explicitly. Create .laravelpint or follow your team's preference.
composer require --dev larastan/larastan
# Ensure pint is installed
composer require --dev laravel/pint
| Feature | Laravel Pint | Larastan / PHPStan |
|---|---|---|
| Purpose | Code Style (Formatting) | Bug Prevention (Slicing logic) |
| Execution Speed | Fast (Millions of lines/hour) | Medium (Analyzes types) |
| Output | New File Contents | Error Reports (Text lines) |
| Issue Type | Subjective (Tabs vs Spaces) | Objective (Logic errors, Refs) |
| Setup Complexity | Low | Moderate (PHPDoc required) |
.neon), not hardcoded in your head.app directory in Laravel 10The next evolution for static analysis in Laravel is Generics for Collections. Currently, working with Eloquent Collections often results in type coercion to ArrayCollection. Future versions of Larastan and PHPStan aim to provide better generics support for specific entity types stored in collections (e.g., UserCollection<User>), further reducing the "mixed" type errors developers currently face.
1. Do I need to add PHPDoc to every method? No, but you do need it for complex closures and return types that aren't inferred. While strict rules suggest documenting everything, starting with PHPStan Level 5 allows you to run initially with implicit returns and gradually migrate to strict documentation.
2. Why do I have broken builds in CI if I'm not changing code? Three reasons:
composer install.3. Is Larastan a fork of PHPStan? No. Larastan is an extension pack that wraps PHPStan and provides additional type rules specifically for Laravel. It requires PHPStan to be installed first. They share a lot of the code under the hood but serve different architectural layers. Larastan handles the integration; PHPStan handles the engine.
4. Can I use Psalm instead of PHPStan?
Yes. You can use Psalm (PsalmTest) instead of PHPStan. It uses a different engine to analyze code. Many high-profile Laravel projects (including various framework internals) use Psalm. The setup flow is identical to Larastan, but the configuration slightly changes in psalm.xml.
5. Does Static Analysis slow down my server? Only during the build process (pre-deployment). It does not run on your production server. However, good static analysis rules can speed up development by letting you know of type errors instantly rather than debugging a cryptic 500 error on a user's screen later.
Wrapping your Laravel application in static analysis in Laravel is no longer optional for senior-level engineering teams; it is standard practice. By installing Larastan and configuring Laravel Pint with an incremental workflow, you capture typos, null pointer exceptions, and style inconsistencies before a single line of code reaches production.
Don't try to boil the ocean. Install the tools, configure them to be lenient locally, and tighten the screws in your CI pipeline. Your future self—and your team members—will thank you.