nunomaduro/larastan
Larastan is a PHPStan extension for Laravel that adds strong type inference and “code analysis” by booting the app container. It understands Laravel’s magic, finds bugs early, and improves code quality and developer productivity.
Installation:
composer require --dev larastan/larastan:^3.0
Ensure your project uses PHP 8.2+ and Laravel 11.15+.
Configure phpstan.neon:
Place this in your project root (or copy from vendor/larastan/larastan/extension.neon):
includes:
- vendor/larastan/larastan/extension.neon
- vendor/nesbot/carbon/extension.neon
parameters:
paths:
- app/
level: 5 # Start with level 5 (moderate strictness)
First Run:
./vendor/bin/phpstan analyse
For memory-heavy projects, add --memory-limit=2G.
Larastan excels at flagging Laravel-specific issues like:
// ❌ Error: Call to undefined method `User::findByEmail()`
$user = User::findByEmail($email);
// ✅ Fix: Use `where()` or `find()` instead
$user = User::where('email', $email)->first();
Pre-Commit Hook:
Add Larastan to your CI/CD pipeline or Git hooks (e.g., husky):
./vendor/bin/phpstan analyse --level=5 --error-format=github
Use --error-format=github for PR-friendly output.
Incremental Analysis: Focus on one file/directory at a time:
./vendor/bin/phpstan analyse app/Http/Controllers --level=8
Model Casting:
Larastan infers cast types automatically. For custom casts, use @method PHPDoc:
/**
* @method static self whereActive(bool $value)
* @phpstan-return self
*/
Query Builder:
Avoid undefined methods like orderByRaw() without arguments:
// ❌ Error: Missing SQL in `orderByRaw()`
$users = User::orderByRaw(); // Fails
// ✅ Fix
$users = User::orderByRaw('created_at DESC');
Service Container:
Resolve bindings with @var hints:
/** @var \Illuminate\Contracts\Auth\Factory $auth */
$auth = app(\Illuminate\Contracts\Auth\Factory::class);
Use Larastan’s custom types to improve type safety:
/**
* @param \Laravel\Fortify\Contracts\CreatesNewUsers $guard
*/
public function register(CreatesNewUsers $guard) { ... }
/**
* @return \Illuminate\Support\Collection<int, \App\Models\User>
*/
public function getActiveUsers(): Collection { ... }
Larastan parses migrations to infer column types:
// ✅ Auto-detected: `$user->email` is `string`
Schema::create('users', function (Blueprint $table) {
$table->string('email');
});
False Positives in Dynamic Code:
app() or config() calls as "undefined."@var hints or @phpstan-ignore-line:
/** @var \Illuminate\Config\Repository $config */
$config = config('app.timezone');
Blade Template Errors:
NoMissingTranslationsRule in phpstan.neon:
parameters:
larastan:
rules:
no_missing_translations: true
Memory Limits:
--memory-limit=4G or analyze files incrementally.Squashed Migrations:
phpmyadmin/sql-parser (optional) for better support:
composer require --dev phpmyadmin/sql-parser
./vendor/bin/phpstan analyse --verbose
./vendor/bin/phpstan analyse --generate-baseline
Then commit phpstan.baseline.neon to version control.Custom Rules: Extend Larastan by creating a custom PHPStan rule (see PHPStan docs).
Override Config:
Disable specific rules in phpstan.neon:
parameters:
larastan:
rules:
no_undefined_model_methods: false
Performance:
enableMigrationCache to speed up repeated runs:
parameters:
larastan:
enableMigrationCache: true
phpstan-baseline:
Use phpstan-baseline to track progress:
composer require --dev phpstan/phpstan-baseline
./vendor/bin/phpstan analyse --baseline=phpstan.baseline.neon
settings.json:
{
"phpstan.executablePath": "./vendor/bin/phpstan",
"phpstan.arguments": ["analyse", "--level=5"]
}
README.md:
[](https://github.com/your-repo/actions/workflows/phpstan.yml)
How can I help you explore Laravel packages today?