Configuration
All options live under parameters.phpstanLaravelValidation. Defaults match
Laravel’s ordinary factory and validator behavior.
parameters:
phpstanLaravelValidation:
laravelVersion: auto
assumeHttpInputNormalization: false
includeUnvalidatedArrayKeys: false
experimentalConditionalPresenceInference: false
formRequests:
enabled: false
trustedClasses: []
customRules:
classes: []
names: []
laravelVersion
Default: auto.
auto uses Composer’s installed-version data for the project root matching
PHPStan’s working directory. That follows the Laravel code actually installed
for analysis rather than a potentially stale lockfile. If no matching
installed-package data is available, the extension falls back to the analyzed
project’s composer.lock. It does not use Laravel versions from unrelated
Composer roots that happen to be loaded in the PHPStan process.
The detected laravel/framework version selects verified release boundaries
such as integer:strict, ascii, and Laravel’s default request-trimming
exceptions. A standalone illuminate/validation installation can select
rule-level behavior, but cannot establish full-framework middleware defaults.
For monorepos or other layouts where PHPStan’s working directory is not the relevant Composer project root, set the version explicitly:
parameters:
phpstanLaravelValidation:
laravelVersion: '13.4.0'
If the version is unavailable, malformed, or outside the supported Laravel 10–13 range, inference retains the conservative cross-version type. The effective version context participates in PHPStan’s result-cache metadata, so changing Laravel versions invalidates cached inference.
Boundaries are listed in Laravel Version Behavior.
assumeHttpInputNormalization
Default: false.
By default the extension models the validator itself and therefore includes
blank strings that can bypass optional non-implicit rules. Applications whose
request validation is guaranteed to run after Laravel’s standard
TrimStrings and ConvertEmptyStringsToNull middleware may opt into
narrower request types:
parameters:
phpstanLaravelValidation:
assumeHttpInputNormalization: true
This option affects Request::validate(), controller validate(), and
inferred FormRequest::validated() calls. It does not affect direct
validators, factories, facades, or validators passed to validateWith().
An optional array field normally has the value type array|string because
a blank string may bypass the rule. With this option it has type array;
nullable|array has type array|null. Laravel 11 through 13 exclude
current_password, password, and password_confirmation from trimming by
default, so those paths still include strings. Laravel 10 trims them and
receives the narrower type. If a supported full-framework version cannot be
established, the extension conservatively includes strings.
Enable this option only if neither middleware is skipped or removed and
validation cannot observe values introduced afterward by request mutation.
Projects with custom trimming exceptions or skipWhen() callbacks should
leave it disabled.
includeUnvalidatedArrayKeys
Default: false, matching Laravel’s factory default.
Laravel’s validation factory excludes unvalidated nested array keys by
default. An application that calls includeUnvalidatedArrayKeys() changes
the shape returned from bare array and, where supported by Laravel, list
parents with nested child rules.
parameters:
phpstanLaravelValidation:
includeUnvalidatedArrayKeys: true
When enabled, the extension conservatively widens affected nested parents
because unmentioned keys may survive in validated(). This applies to
inferred factory, facade, request, controller, validator-helper, and
FormRequest output. Affected bare array parents widen to array, so the
inferred types of their validated children are no longer retained. Bare
list parents retain only their listness unless a direct exclusion rule can
remove an element.
The extension does not boot the application or attempt to discover a call in
a service provider. Treat this option as an assertion about the factories
whose output the extension infers. It is not a conservative setting for mixed
factory modes. In particular, an excluding factory can reconstruct a bare
list parent with sparse keys. An including factory normally preserves the
parent, but nested exclusion rules mutate its data before validated()
reads it and can also make the result sparse. The extension widens parents
with direct exclusion rules to cover that behavior. A single global option
cannot precisely model mixed factory modes. A directly constructed
Illuminate\Validation\Validator retains Laravel’s broad declared return
type and is not narrowed from this assumption.
PHPStan reports laravelValidation.unvalidatedArrayKeysConfiguration when a
direct Factory method call or statically resolved Validator facade call
switches to the mode opposite this option. The diagnostic is call-local: it
does not execute service providers, follow arbitrary container aliases, or
claim to determine the final mode after later calls. The option remains the
source of truth for inferred output.
experimentalConditionalPresenceInference
Default: false.
Laravel’s dependent presence rules normally leave the affected output key optional because their result depends on another runtime value. This option recovers definite cases where a required top-level controlling field has a finite scalar-literal type.
parameters:
phpstanLaravelValidation:
experimentalConditionalPresenceInference: true
$validated = Validator::make($input, [
'mode' => 'required|string|in:create',
'name' => 'present_if:mode,create|string',
])->validated();
\PHPStan\dumpType($validated);
// array{mode: 'create', name: string}
The option handles definite outcomes for present_if, present_unless,
missing_if, and missing_unless. Active presence requires the key but
still permits blank strings to bypass adjacent non-implicit rules; it is not
treated as required. Active missing rules omit the key from successful
output. present_if and present_unless refinement requires a detected
Laravel version of 10.32 or later; earlier or unknown versions remain
conservative.
The first experimental slice supports only one conditional field whose controller is a required direct top-level sibling. The controller’s entire inferred domain must either match or not match the dependent values. Mixed matching and non-matching domains, boolean controllers, nested or wildcard paths, multiple conditional fields, exclusions, and custom or opaque rules retain the ordinary conservative optional shape.
See Presence and Output Projection.
Form requests
See FormRequest Inference for behavior. The keys are:
parameters:
phpstanLaravelValidation:
formRequests:
enabled: false
trustedClasses: []
trustedClasses is an exact class list. Subclasses are not trusted
implicitly.
Custom rules
parameters:
phpstanLaravelValidation:
customRules:
classes: []
names: []