jbboehr / phpstan-laravel-validation
Laravel Validation extension for PHPStan
Package info
github.com/jbboehr/phpstan-laravel-validation
Type:phpstan-extension
pkg:composer/jbboehr/phpstan-laravel-validation
Requires
- php: ^8.1
- composer-runtime-api: ^2.1
- nikic/php-parser: ^4.15 || ^5.1
- phpstan/phpstan: ^2.1.5
Requires (Dev)
- brick/varexporter: ^0.6.0
- giorgiosironi/eris: ^1.1
- illuminate/http: ^10.0 || ^11.0 || ^12.0 || ^13.0
- illuminate/validation: ^10.0 || ^11.0 || ^12.0 || ^13.0
- jbboehr/akashi: dev-master
- jbboehr/doctrine-of-the-second-sun: dev-master
- laravel/framework: ^10.0 || ^11.0 || ^12.0 || ^13.0
- php-cs-fixer/shim: ^3
- phpstan/phpstan-phpunit: ^2.0
- phpstan/phpstan-strict-rules: ^2.0
- phpunit/phpunit: ^10.0
This package is auto-updated.
Last update: 2026-08-27 04:10:05 UTC
README
phpstan-laravel-validation
Caution
CONSIDER AN ALTERNATIVE FOR NEW CODE
Laravel validation is not a typed data boundary. Successful validation commonly preserves original values rather than producing the native PHP types suggested by rule names. Presence conditions, cross-field rules, wildcards, exclusions, and nested projection can also change the returned shape in surprising ways.
phpstan-laravel-validation aims to recover sound and useful structural types from that behavior. Some inferred types are necessarily broader than expected because they describe what Laravel can actually return.
For new type-conscious code, consider a boundary with an explicit, normalized output contract, such as cuyz/valinor, typed DTOs, schema objects, or explicit parsers.
See Laravel validation and type safety for verified examples and the detailed rationale.
This library is a mitigation, not an endorsement of Laravel validation for new code.
Should I use it?
Use this extension when an existing application already validates with
Laravel and you want PHPStan to describe the successful validated()
shape honestly.
Do not use it as a reason to keep Laravel validation as the typed boundary for new code. Prefer an explicit, normalized output contract there. This package is a mitigation layer.
What this extension does
For supported, statically resolvable rule expressions, this PHPStan 2.x extension infers a sound type for Laravel's validated output. Every successful Laravel value must be a subtype of that type. The inferred type may be broader than a rule name suggests because Laravel preserves input types and can produce dynamic output shapes.
$request = new \Illuminate\Http\Request(); $data = \Illuminate\Support\Facades\Validator::make($request->all(), [ 'person' => 'required|array', 'person.*.email' => 'required|string|email|unique:users', 'person.*.first_name' => 'required|string', 'person.*.age' => 'required|integer|string', ])->validated(); \PHPStan\dumpType($data); // array{person: array<int|string, array{email: non-empty-string, first_name: string, age: numeric-string}>}
The explicit person rule makes that offset required. Without it, wildcard
rules only constrain matching elements, so the inferred shape uses
person?.
The same rule-set inference applies to factory make() / validate(),
Request::validate(), and controller validate(). Dynamic or unpacked
rule sets retain Laravel's broad declared return types.
A successful direct facade or Factory::validate() call can also refine
safe top-level fields on the caller's original array. That is an input
constraint, not a claim that the array was replaced by validated()
output. Details are in
Supported Entry Points.
Installation
Requires PHP 8.1. Supported on PHP 8.1 through 8.5, PHPStan 2.1.5 or later, and Laravel 10 through 13.
composer require --dev jbboehr/phpstan-laravel-validation
If you also install phpstan/extension-installer, the extension is registered automatically.
Otherwise include extension.neon in your PHPStan config:
includes: - vendor/jbboehr/phpstan-laravel-validation/extension.neon
Configuration
Defaults match Laravel's ordinary factory and validator behavior. Most projects can start with no extra options.
parameters: phpstanLaravelValidation: laravelVersion: auto
Set laravelVersion explicitly when PHPStan's working directory is not
the Composer project that owns Laravel. Opt into
assumeHttpInputNormalization only when request validation always runs
after Laravel's default trim/empty-string middleware. FormRequest inference
and definite conditional-presence inference are experimental and off by
default.
The full option list is in Configuration.
Status
The 0.1 line is an experimental public release.
- PHP 8.1 through 8.5
- PHPStan 2.1.5 or later
- Laravel 10 through 13
Sound inferred types may be broader than rule names suggest. Dynamic rule construction, callbacks, and custom rules without an accurate static contract stay conservative. See Limitations and Laravel Version Behavior.
Documentation
The published book is
https://jbboehr.github.io/phpstan-laravel-validation/.
Source pages live under docs/pages/:
- Getting Started
- Understanding Inferred Types
- Laravel Validation and Type Safety
- FormRequest Inference
- Custom Validation Rules
- Validation Rules
- Rule Builders
- Static Resolvability
- Testing and Runtime Verification
Development
nix develop composer install nix flake check --keep-going -L
See Development and CONTRIBUTING.md.
License
This project is licensed under the AGPL v3+ License - see the LICENSE.md file for details.
