Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Pest Plugin Phpstan Laravel Package

pestphp/pest-plugin-phpstan

A Pest plugin that brings PHPStan static analysis into your Pest test suite, letting you run and assert PHPStan results directly from tests. Integrate type and error checks into your workflow without leaving Pest.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the plugin alongside PHPStan itself — the plugin is a thin bridge, not a replacement for PHPStan:

composer require --dev pestphp/pest-plugin-phpstan phpstan/phpstan
# Laravel projects: use Larastan instead of raw PHPStan rules
composer require --dev larastan/larastan

The plugin registers a --phpstan flag on the Pest binary. Your first run is:

./vendor/bin/pest --phpstan

That single command runs your test suite and hands your configured paths to PHPStan, so a green build means "tests pass and static analysis is clean."

Where to look first (in order):

  1. vendor/pestphp/pest-plugin-phpstan/src/ — the plugin is small; read the service provider/console option registration to see exactly what flags and defaults your installed version supports.
  2. vendor/pestphp/pest-plugin-phpstan/README.md — usually the only documentation; confirm the Pest major version it targets.
  3. Your project root for phpstan.neon / phpstan.neon.dist — the plugin delegates all analysis config here. If you don't have one, create it before expecting useful results.

Minimal working config (phpstan.neon.dist at project root):

parameters:
    level: 6
    paths:
        - app
        - src
    # Laravel only:
    # includes:
    #     - vendor/larastan/larastan/extension.neon

First real use case: wire pest --phpstan into your pre-push habit or CI job so type regressions are caught in the same gate as behavioural regressions. Start at level 5–6 with a baseline, not level 9 on day one.

Implementation Patterns

Composer script as the team-facing entry point. Don't make people remember flags:

"scripts": {
    "test": "@php vendor/bin/pest",
    "analyse": "@php vendor/bin/pest --phpstan",
    "analyse:only": "@php vendor/bin/phpstan analyse --memory-limit=1G"
}

CI: split the signals, keep the combined gate. Use the plugin for the "does everything pass" job, but emit PHPStan output separately so failures are attributable:

- run: ./vendor/bin/phpstan analyse --no-progress --error-format=github
- run: ./vendor/bin/pest --phpstan --ci

If you only have one step, at minimum capture the exit code and the tail of output — combined runs can make it ambiguous whether tests or analysis failed.

Baseline-first adoption. On an existing codebase, generate a baseline rather than lowering the level:

./vendor/bin/phpstan analyse --generate-baseline
# commit phpstan-baseline.neon, reference it in phpstan.neon

Then ratchet the level up over time and prune the baseline during refactors. A baseline that only shrinks is a healthy one.

Laravel/Larastan specifics. Include the Larastan extension, bootstrap the framework for accurate container/model resolution, and expect to need a higher memory limit:

includes:
    - vendor/larastan/larastan/extension.neon
parameters:
    level: 6
    paths: [app]
    bootstrapFiles:
        - vendor/larastan/larastan/bootstrap.php

Complement, don't duplicate, Pest's own features. Arch tests (arch()->preset()->laravel()) cover naming/structure; PHPStan covers types and nullability; pest-plugin-type-coverage covers the ratio of typed code. Run all three, but don't re-implement one in another.

Local loop discipline. Run pest --phpstan before opening a PR; run raw phpstan analyse path/to/File.php while iterating on a single file (faster feedback than the combined command). Inline suppressions are the escape hatch, not the strategy:

/** @phpstan-ignore-next-line */
$this->legacyService()->doThing();

Prefer targeted ignoreErrors entries in phpstan.neon (with path and message regexes) over blanket ignores.

Parallelism is two separate knobs. Pest's --parallel controls test workers; PHPStan's parallelism lives in phpstan.neon (parallel.maximumNumberOfProcesses). Don't assume one tunes the other.

Gotchas and Tips

  • This is an 11-star plugin. Treat it as convenience glue, not infrastructure. Pin the exact version in composer.json, and be prepared to fall back to running phpstan and pest as two separate commands if a Pest upgrade breaks the flag. Have that fallback in CI from day one.
  • Version lockstep is the main failure mode. The plugin must match your Pest major (v2 vs v3) and tolerate your PHPStan major (1.x vs 2.x). After any composer update, immediately re-run pest --phpstan — a silently ignored flag is the most common symptom of a mismatch. Verify with ./vendor/bin/pest --help | grep phpstan.
  • --filter and --group do not scope analysis. Those are Pest test selectors; PHPStan analyses whatever paths says in phpstan.neon. If you expect "analyse only the files I'm testing," you'll be surprised — use phpstan analyse <path> directly for that.
  • Memory. PHPStan on a Laravel app routinely needs >1G. Set --memory-limit=1G or memory_limit in phpstan.neon; otherwise you'll get a fatal error that looks like a plugin crash.
  • Stale cache. PHPStan caches in tmpDir (default under sys_get_temp_dir()). When results look impossible — phantom errors, or errors that won't clear after a fix — delete the cache dir or run with --debug. In CI, avoid caching PHPStan's tmp dir across jobs unless you're sure of the key.
  • Exit codes and output interleaving. In a combined run, PHPStan's table and Pest's progress output can interleave badly in CI logs. Prefer --error-format=github or --no-progress when you need machine-readable output.
  • Baseline drift. reportUnmatchedIgnoredErrors: true (the default) will fail the build when a baselined error disappears. That's useful — it forces baseline pruning — but it surprises people mid-refactor. Know the setting before you file a bug against the plugin.
  • Extension points are PHPStan's, not the plugin's. Custom rules, @phpstan- annotations, stub files, and services: in phpstan.neon all work exactly as in vanilla PHPStan, because the plugin doesn't intercept them. If you need behaviour the plugin doesn't expose, write it as a PHPStan rule/config — don't wait for a plugin release.
  • IDE experience is unaffected. The plugin is a CLI convenience; it gives you nothing in the editor. Keep the PHPStan/Intelephense/PHPStorm inspection setup separate and configured from the same phpstan.neon.
  • Docs are thin — read the source. When the README is ambiguous about flag behaviour, vendor/pestphp/pest-plugin-phpstan/src is a few hundred lines at most and is the authoritative answer for your locked version.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect