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

Phpstan React Laravel Package

wyrihaximus/phpstan-react

PHPStan extension for ReactPHP projects that flags blocking PHP functions such as file_get_contents, fopen, and fclose, and points to async ReactPHP replacements from react/filesystem and react/socket. Install via Composer; rules auto-load with phpstan/extension-installer or include extension.neon.

View on GitHub
Deep Wiki
Context7

Getting Started

Add it as a development-only dependency, it ships no runtime code and has no Laravel service provider:

composer require --dev wyrihaximus/phpstan-react

If phpstan/extension-installer is already in your project (common in Laravel apps running Larastan), the rules load automatically and you are done. Otherwise wire it up manually in phpstan.neon:

includes:
    - vendor/larastan/larastan/extension.neon
    - vendor/wyrihaximus/phpstan-react/extension.neon

parameters:
    level: 8

Note the include path: earlier docs pointed at the wrong file and that was only fixed in 3.0.0, so make sure you are on ^3.0 and that the path is vendor/wyrihaximus/phpstan-react/extension.neon.

Where to look first:

  1. vendor/wyrihaximus/phpstan-react/extension.neon for the real parameter keys, since the README documents rules but not the toggles.
  2. The function table in the README to understand the replacement mapping (file_get_contents to React\Filesystem\Node\FileInterface::getContents, sleep/usleep to React\Promise\Timer\sleep, gethostbyname to React\Dns\ResolverInterface::resolve, and so on).
  3. parameters.wyrihaximus.reactphp.rules for the per-category switches added in 3.0.

First useful use case: you have a long-running ReactPHP process in a Laravel codebase. That is almost always Laravel Reverb internals, a custom artisan daemon command, a queue consumer built on react/event-loop, or a package you maintain that exposes ReactPHP APIs. Run vendor/bin/phpstan analyse and the blocking calls in those paths light up. On a plain request/response Laravel app with no event loop code anywhere, this package gives you nothing; skip it.

Implementation Patterns

Scope the analysis to the ReactPHP subsystem. Do not enable this for the whole codebase. Blocking calls are correct and expected in HTTP controllers, console commands and bootstrapping. Keep a dedicated config and run it as its own CI job:

# phpstan-react.neon
includes:
    - vendor/wyrihaximus/phpstan-react/extension.neon

parameters:
    level: max
    paths:
        - src/Reactor
        - src/Streams
    ignoreErrors:
        - # bootstrap runs before the loop starts
            message: '#file_get_contents#'
            path: src/Reactor/Bootstrap.php

Then vendor/bin/phpstan analyse -c phpstan-react.neon alongside your normal Larastan run.

Treat the reports as an architecture boundary, not a bug list. The blocking-function rules are there to stop I/O creeping into handlers that run inside the loop. The practical workflow is: keep cold-path I/O (config, env, container wiring, one-off CLI bootstrapping) outside the analyzed paths, keep hot-path code inside them, and convert anything flagged to its react/* equivalent. A file_get_contents inside a timer callback is a real latency bug, a file_get_contents in artisan bootstrapping is fine.

Adopt the 3.0 event-loop rules as a style gate. The 3.0 release added rules that encode "the loop is global, reach it through Loop::...". That means it will flag injected LoopInterface constructor parameters, promoted properties and traits holding a loop reference, Loop::get() indirection, and method calls on values typed as LoopInterface. The pattern it pushes you toward is:

use React\EventLoop\Loop;

Loop::addTimer(1.0, function (): void {
    // static facade, no loop passed around
});

If your Reverb-adjacent classes currently take a loop in the constructor, expect noise on the first run. Either refactor to the static facade (preferred, the rules exist for lifetime reasons) or disable that rules category first and migrate deliberately.

Roll out the async/fiber rules separately. 3.0 also tracks async() closures with a parser visitor and a call-graph collector, flagging await outside an async closure and plain closures that can reach await indirectly. Indirect reachability analysis across call graphs is the noisiest category, so gate it behind its own config flag on your first adoption and turn it on for a smaller path set once you see what it reports.

Pin the pair in CI. Because the analysis depends on internal PHPStan parser visitors, run composer update for PHPStan and this extension together and re-run the react config in the same PR. Version skew is the only realistic way to get a confusing failure out of this package.

Gotchas and Tips

  • No identifiers documented. The README lists functions and suggested replacements but not the PHPStan error identifiers. Get them quickly with vendor/bin/phpstan analyse -c phpstan-react.neon --error-format=json | jq '.files[].messages[] | .identifier' and ignore by identifier rather than by message text, which survives rewording.
  • Double inclusion. With phpstan/extension-installer present, adding the neon manually is redundant. Harmless, but if rules seem to fire twice or config overrides do not apply, check whether you included it twice.
  • fopen/fread/fwrite false positives. Stream-based code that is genuinely correct (custom stream wrappers, protocol codecs that must decode synchronously) will be flagged. fopen maps to both react/filesystem and react/socket, so the suggestion may not fit your case at all. Ignore per-path.
  • Runtime context is invisible to the analyser. It cannot know whether a function executes inside a fiber, a timer callback, or before Loop::run(). Expect a few legitimate blocking calls to need suppression, and document why in the ignore comment so the next developer does not re-litigate it.
  • The toggles are undocumented prose. The 3.0 release notes mention parameters.wyrihaximus.reactphp.rules but not its shape. Read the extension.neon shipped in vendor/ for the actual keys before guessing, and keep the disabled categories in a comment in your neon so the reason survives.
  • Do not expect Loop::stop() linting. The author's conventions (shutdown by removing loop subscribers, never Loop::stop()) are house rules, not enforced rules. No coverage here.
  • Tiny maintenance surface. Two stars, zero dependents, one maintainer. Keep it in require-dev, do not build a critical gate on it without a fallback, and remember that the whole blocking-function layer is reproducible with a handful of ignoreErrors entries if the package ever stalls.
  • Extension points. All the per-function data was moved into a data file in PR #64 in preparation for new features; if you need a custom blocking function flagged, that data file is where to look before writing your own rule.
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.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums