nunomaduro/larastan
Larastan is a PHPStan extension for Laravel that analyzes your app to catch bugs early. It boots the container to resolve dynamic types, supports Laravel’s “magic,” and improves code quality with stronger static typing.
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
Use --memory-limit=2G if you hit memory issues.
Run Larastan on a controller with known issues (e.g., undefined methods or incorrect return types):
./vendor/bin/phpstan analyse app/Http/Controllers/
Example error caught:
Call to undefined method App\Models\User::nonExistentMethod()
Pre-Commit Hook:
Add Larastan to your CI/CD pipeline or Git hooks (e.g., using phpstan in .git/hooks/pre-commit):
#!/bin/bash
./vendor/bin/phpstan analyse --level=5 --error-format=github
Configure Git to auto-format errors as GitHub annotations.
IDE Integration:
Use PHPStan’s IDE plugins (e.g., PHPStan for PHPStorm) for real-time feedback.
Example .phpstorm.meta.php snippet for Laravel:
namespace PHPStormMeta {
override(type('App\Models\User'), method('findOrFail(int $id)')) {
return type('App\Models\User');
}
}
Model Property Checks:
Enable strict model property validation in phpstan.neon:
parameters:
checkModelProperties: true
checkModelAppends: true
Example: Catches incorrect casts or missing attributes:
Property App\Models\User::$nonExistentAttribute does not exist.
Collection Optimization:
Use noUnnecessaryCollectionCall to flag redundant collection methods:
parameters:
noUnnecessaryCollectionCallOnly:
- 'pluck'
- 'map'
Example error:
Unnecessary call to Collection::pluck('id') when $user->id is directly accessible.
Strict Config Type Checking: Enable to catch misused config values:
parameters:
checkConfigTypes: true
configDirectories:
- config/
- modules/*/config
Example error:
Parameter #1 (array{guard: 'web'}) of echo cannot be converted to string.
Environment Variable Generalization:
Simplify env() return types with defaults:
parameters:
generalizeEnvReturnType: true
Example:
$timeout = env('APP_TIMEOUT', 30); // Inferred as `int` instead of `string|int`
Custom Migration Paths: For modular apps, specify migration paths:
parameters:
databaseMigrationsPath:
- app/Domain/Auth/migrations
- packages/*/migrations
squashedMigrationsPath:
- database/schema
Enable caching for performance:
parameters:
enableMigrationCache: true
PostgreSQL Support:
Install phpmyadmin/sql-parser for better schema parsing:
composer require phpmyadmin/sql-parser:^5.9
Regenerate autoload:
composer dump-autoload
Generate Baseline: For legacy codebases, create a baseline to ignore existing issues:
./vendor/bin/phpstan analyse --generate-baseline
Commit baseline.neon to version control and gradually fix errors.
Selective Analysis: Focus on critical paths first:
./vendor/bin/phpstan analyse app/Http/Controllers/ --level=8
Memory Limits:
--memory-limit=4G or split analysis by directory.excludePaths:
- tests/
- vendor/
False Positives in Magic Methods:
fillable, accessors) may trigger errors.phpstan.neon:
ignoreErrors:
- '#Call to an undefined method Illuminate\\Database\\Eloquent\\Model::fillable#'
Performance Overhead:
parseModelCastsMethod or checkConfigTypes slows analysis../vendor/bin/phpstan analyse --disable-extension=larastan
PostgreSQL Schema Parsing:
laravel-ide-helper for PHPDoc generation or simplify schemas.Verbose Output:
Run with --verbose to debug extension loading:
./vendor/bin/phpstan analyse --verbose
Isolate Errors:
Use --focus to target specific files/classes:
./vendor/bin/phpstan analyse app/Models/User.php --focus
Custom Rules: Extend Larastan’s rules by creating a custom extension:
// app/Rules/CustomLarastanRule.php
use PHPStan\Rules\Rule;
use PHPStan\Analyser\Scope;
class CustomLarastanRule implements Rule {
public function getNodeType(): string { return 'Php\Method'; }
public function process(Node $node, Scope $scope) { /* ... */ }
}
Register in phpstan.neon:
includes:
- app/Rules/CustomLarastanRule.neon
Custom PHPDoc Types: Extend Larastan’s types (e.g., for custom casts):
/**
* @phpstan-type CustomCast array{type: string, options: array}
*/
Override Laravel Types:
Use @method or @property in PHPDoc to guide Larastan:
/**
* @property-read string $custom_attribute
* @method static self findByCustomAttribute(string $value)
*/
class User extends Model {}
Dynamic Container Resolution:
For services resolved via the container, use @var hints:
/** @var \Illuminate\Contracts\Auth\Factory $auth */
$auth = app('auth');
Pair with phpstan-baseline:
Use phpstan/phpstan-baseline to track progress:
composer require --dev phpstan/phpstan-baseline
./vendor/bin/phpstan analyse --baseline=baseline.neon
Laravel IDE Helper:
Combine with barryvdh/laravel-ide-helper for PHPDoc generation:
composer require barryvdh/laravel-ide-helper
php artisan ide-helper:generate
CI Optimization: Cache PHPStan results in CI (e.g., GitHub Actions):
# .github/workflows/phpstan.yml
jobs:
phpstan:
runs-on: ubuntu-latest
steps:
- uses: actions/cache@v3
with:
path: ~/.phpstan/cache
key: phpstan-${{ hashFiles('composer.lock') }}
How can I help you explore Laravel packages today?