Skip to content

Latest commit

 

History

214 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Inferences for Laravel Validation + PHPStan

phpstan-laravel-validation

ci License: AGPL v3+ stability-experimental AI burn

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 your application uses the experimental jbboehr\Rensei\Parse runtime, install this package without --dev so it remains available in production. See Parsing Validated Output for installation details and runtime requirements.

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/:

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.

About

Experimental phpstan plugin for Laravel Validation

Topics

Resources

Contributing

Stars

9 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages