jbboehr/phpstan-laravel-validation

Laravel Validation extension for PHPStan

Maintainers

Package info

github.com/jbboehr/phpstan-laravel-validation

Type:phpstan-extension

pkg:composer/jbboehr/phpstan-laravel-validation

Transparency log

Statistics

Installs: 10 052

Dependents: 0

Suggesters: 0

Stars: 6

Open Issues: 0

v0.1.0 2026-08-16 02:16 UTC

This package is auto-updated.

Last update: 2026-08-26 08:19:19 UTC


README

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 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.