canvural/larastan-strict-rules
Extra strict, opinionated PHPStan rules for Laravel via Larastan. Enforce safer patterns by banning dynamic where methods, facades, and global helpers; prevent validation in controllers; ensure scopes return Eloquent Builder. Enable all at once or toggle rules individually.
composer require --dev canvural/larastan-strict-rules
phpstan.neon):
includes:
- vendor/canvural/larastan-strict-rules/rules.neon
vendor/bin/phpstan analyse
Start with NoFacadeRule to enforce dependency injection over facades:
// Before (flagged)
$users = User::all();
// After (recommended)
$users = app(User::class)->all();
allRules and enabling specific rules:
parameters:
larastanStrictRules:
allRules: false
noFacade: true
noGlobalLaravelFunction: true
Route::get() with dependency-injected Router:
// Before
Route::get('/users', [UserController::class, 'index']);
// After (in routes file)
$router->get('/users', [UserController::class, 'index']);
app/Http/Requests/StoreUserRequest):
public function rules(): array {
return ['email' => 'required|email'];
}
Controller becomes:
public function store(StoreUserRequest $request) {
// No manual validation needed
}
phpstan-soft for gradual enforcement:
level: 8
strictness: soft
allowedGlobalFunctions for exceptions (e.g., auth()):
parameters:
allowedGlobalFunctions:
- auth
False Positives in NoDynamicWhereRule:
User::published()) may trigger this rule. Exclude them via:
parameters:
larastanStrictRules:
noDynamicWhere: false
Builder explicitly:
public function scopePublished($query) {
return $query->where('published', true);
}
Listener Paths Misconfiguration:
listenerPaths for ListenerShouldHaveVoidReturnTypeRule will silently ignore the rule.parameters:
listenerPaths:
- app/Listeners
- app/Events
Property Accessors:
NoPropertyAccessorRule blocks both definition and usage:
// Both flagged:
protected $attributes = ['name' => 'Can'];
public function getNameAttribute() { ... }
--error-format=github for clear PR feedback:
vendor/bin/phpstan analyse --error-format=github
parameters:
larastanStrictRules:
allRules: false
Custom Rules:
Extend the package by creating a custom Rule class (e.g., NoHardcodedRoutesRule) and include it in rules.neon:
includes:
- vendor/canvural/larastan-strict-rules/rules.neon
- app/Rules/CustomRule.neon
Override Rule Logic:
Fork the package and modify NoFacadeRule to allow specific facades (e.g., Cache::remember()).
phpstan.neon:
scanFileInfo: false
orchestra/testbench is updated (see changelog).NoDynamicWhereRule may conflict with dynamic methods like whereHas() or with(). Exclude them via:
parameters:
larastanStrictRules:
noDynamicWhere: false
How can I help you explore Laravel packages today?