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

Technical Evaluation

Architecture fit. wyrihaximus/phpstan-react is a static-analysis plugin, not a runtime library. It ships a extension.neon that registers PHPStan rules which (a) flag blocking PHP functions (sleep, file_get_contents, fopen, gethostbyname, and similar) inside ReactPHP code and (b) in 3.0.0 add event-loop architectural rules (prefer Loop::… static access, forbid Loop::get() indirection, forbid injecting or promoting LoopInterface, forbid holding a loop in a property or trait) plus react/async fiber rules that detect await used outside an async closure or reachable indirectly through the call graph.

Structurally this is a dev-only dependency (require-dev) with zero production artifact. That is the single most important architectural fact: it cannot affect runtime behavior, deployment surface, or request latency. Its only coupling is to PHPStan's internal rule API and the ReactPHP type definitions that must already be present in the project.

The fit problem is domain, not code. Laravel is a synchronous request/queue framework; the ReactPHP event loop is not part of a normal Laravel lifecycle (FPM or Octane/Swoole). The extension only produces signal in the narrow slice of a codebase that actually runs ReactPHP: a custom event-loop server, react/http/react/socket services, async CLI daemons, or a Laravel component that consumes a ReactPHP-based client. Outside those directories it will mostly generate noise, because idiomatic Laravel code legitimately calls file_get_contents, mkdir, and sleep in blocking contexts.

Integration feasibility. Low effort. Composer install plus either the phpstan/extension-installer convention or an explicit includes: entry. The real integration work is scoping and sequencing, not wiring: paths/excludePaths must be narrowed to the async-facing directories, and parameters.wyrihaximus.reactphp.rules must be used to enable the rule categories one at a time (blocking-function rules first, event-loop rules second, async/await rules last, since the call-graph-based await reachability check is the most heuristic and the likeliest source of false positives).

Technical risk.

  • Version coupling to PHPStan internals. Parser visitors and call-graph collectors are the least stable corners of the PHPStan extension API. Major PHPStan releases can break rule registration or type resolution in ways that fail loudly (crash) or, worse, fail silently (rule stops firing).
  • Conflation risk with Larastan. Both are PHPStan extensions in the same config graph. Larastan already pins PHPStan to a supported range, so Composer resolution is the first thing to prove, followed by rule-ordering and duplicate-diagnostic behavior.
  • False positives on the async rules. The "closure can reach await indirectly" analysis is a transitive approximation; it will be wrong on dynamically dispatched calls, containers, and callbacks registered through Laravel's service container.
  • Bus factor. Two stars, zero dependents, effectively a single maintainer. The code quality signals are strong (49 PRs in 3.0.0, Renovate-driven dependency hygiene, MIT, CI badge, current PHP support), but there is no downstream community acting as a regression net.
  • Fails open. If the includes: line is dropped or the installer convention is disabled, the plugin silently does nothing. There is no signal that analysis has been lost.

Key questions for the evaluation.

  1. Which repositories, if any, actually contain ReactPHP code paths, and are they inside the PHPStan paths we would scope to?
  2. Which PHPStan major and minor does our Larastan version pin, and does this extension declare compatibility with it?
  3. Do we run phpstan/extension-installer today, or hand-curate includes:? If the latter, who owns keeping that line correct?
  4. What is the current count of blocking-function diagnostics in the scoped directories, and are they legitimate (must fix) or unavoidable (must baseline)?
  5. If we are on Octane rather than ReactPHP, is there any code in scope at all, or is this a theoretical adoption?
  6. Can we accept a single-maintainer dependency in CI, and is our fallback simply removing the plugin if a PHPStan upgrade breaks it?

Integration Approach

Stack fit. Treat this as a CI/lint-layer component alongside PHPStan, Larastan, Pint, and Rector. It belongs in require-dev, pinned with a caret constraint and refreshed by Renovate/Dependabot exactly like the rest of the QA toolchain. It does not belong in any deployable image, and it should not be a dependency of application packages that get published.

Migration path.

  1. Qualify. Grep the candidate repository for React\, Loop::, react/, and async(. If the result set is empty or trivial, stop. The opportunity score is high, but the adoption signal (two stars, zero dependents) means we absorb all discovery risk ourselves.
  2. Prove resolution. Add to require-dev on a branch and run composer update --dry-run against the existing Larastan/PHPStan constraint set. Any conflict here ends the evaluation cheaply.
  3. Wire with explicit includes. Prefer an explicit includes: entry over relying on extension-installer auto-discovery, so the config is greppable and the omission is visible in review.
  4. Scope hard. Restrict analysis to the async-facing directories via a dedicated PHPStan config or path set. Do not enable the extension on the whole app/ tree; that path leads to a baseline full of Laravel-idiomatic blocking calls and destroys credibility for the tool.
  5. Enable by category. Start with blocking-function rules only. Land fixes or baseline entries. Then enable event-loop rules, which are architectural and will surface design decisions (LoopInterface promoted properties, loop passed through constructors) that need human judgment, not bulk edits. Enable async/await rules last and only if react/async is genuinely in use.
  6. Ratchet. Once green, fail the build on new violations. Re-baseline is a reviewed change, not an automatic one.

Compatibility. Two axes to verify rather than assume: PHPStan major version support declared in composer.json, and the ReactPHP package versions whose types the rules reference. If the project uses react/filesystem, react/socket, react/dns, react/stream, react/promise-timer, or react/async at versions older than the ones the suggested replacements come from, the diagnostic will point at an API that does not exist in that codebase. That is a documentation-quality issue that turns into a support burden.

Sequencing. Because the extension is inert without includes:, the rollout order should be: dependency added and locked, config included but scoped to a single directory, baseline generated, CI gate turned on for that directory only, then widen. Widening should be a deliberate PR per directory, not a config change bundled into a feature branch.

Operational Impact

Maintenance. Low, with one caveat. Routine upkeep is Renovate-shaped: version bumps arrive as PRs and CI tells you if a PHPStan upgrade broke the plugin. The caveat is that the plugin's own release cadence is bot-driven and frequent, so the diff noise in composer.lock will be constant. Budget a small recurring line item for "QA toolchain maintenance" and route these into the existing dependency-update lane rather than treating them as project work.

Support. Effectively none. MIT, no commercial backing, no dependents to consult, single maintainer. The mitigation is architectural, not contractual: because the package is require-dev and scoped to a few directories, removal is always a viable answer to any unresolvable problem. Write that down as the explicit fallback so no one treats an upstream stall as a blocker.

Scaling. The plugin has no runtime cost and only affects CI wall-clock time proportional to the number of files in scope. The scaling concern is organizational, not technical: every additional repository that adopts it needs the same scoping and baseline discipline, or the shared PHPStan config drifts into a state where the rules are either noisy or silently off. If more than a couple of repos adopt it, centralize the config in a shared QA package rather than copy-pasting extension.neon includes.

Failure modes.

  • Silent no-op: include removed or extension-installer disabled. Detect by asserting a known violation still fails in a smoke test, or by treating the PHPStan config as code with review ownership.
  • Crash on PHPStan major upgrade: rule registration or visitor signature changes. Detect via CI; remediate by pinning the previous PHPStan minor until upstream catches up.
  • False-positive storm from the async call-graph rules: highest-probability incident. Mitigate by leaving those rules off until a team has ReactPHP fluency, then enabling with a scoped baseline.
  • Diagnostics pointing at replacement APIs not present in the codebase: degrades developer trust in the tool faster than a crash does, because it looks like the tool is wrong.
  • Dependency-resolution conflict with Larastan: low probability but blocks the whole PHPStan pipeline, so fail fast on a branch before committing.

Ramp-up. The mechanics are trivial for anyone who has added a PHPStan extension (an hour). The interpretation is not: acting on the event-loop and async findings requires genuine ReactPHP fluency, because the correct fix is usually a structural change (stop passing the loop around, move work into an async closure, replace a blocking call with a promise-returning one) rather than a mechanical substitution. The blocking-function rules are the exception; they are self-explanatory and the README maps each function to a documented replacement. Plan for a ReactPHP-literate owner in the one repo that pilots this, and do not roll it out org-wide before that person has validated the signal-to-noise ratio.

Recommendation. Pilot, do not adopt by default. The package is technically sound, cheap to try, and cheap to remove, which makes the downside near zero. The upside is also conditional: it is valuable only where ReactPHP is real, and the near-zero community adoption means the team carries the discovery cost. Recommend a time-boxed pilot in the single repository with actual event-loop code, gated on Composer resolution against the existing Larastan/PHPStan stack, with blocking-function rules enabled first and a documented removal fallback. For the broader Laravel estate (FPM or Octane), defer: the extension's blocking-call rules do not correctly model those runtimes, and enabling them would produce findings that are true in the abstract but wrong for the execution model in use.

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.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
adachsoft/php-code-style