nunomaduro/laravel-code-analyse
Laravel Code Analyse brings static code analysis to your Laravel apps. Run the artisan command to scan your codebase against configurable checks, catch common issues early, and keep your code clean, consistent, and production-ready.
Where to spend engineering time on quality. This is a development-only static analysis layer that finds defects in Laravel code without running it. It pays off most in Eloquent-heavy code — relationship shapes, eager-loading, query builders, facades, collections — which is exactly the layer unit tests under-cover. If the roadmap contains "reduce production defects" or "make refactoring safer," this is the cheapest lever on the list: no runtime surface, no migration, reversible by deleting a require-dev line.
Build vs. buy on Laravel-specific type intelligence. The alternative is owning bespoke PHPStan rules and stubs for facades, models, relationships, and the container forever. Release v3.13.0 retires a meaningful slice of that work directly — the relation-of<Model, Relationship> custom type, inferred relationship types inside with(), withOnly(), load(), and loadMissing() arrays, corrected collection key types for concat(), merge(), shift(), and splice(), and correct resolution of forwarded builder calls through toBase(). That is a clear buy-and-adopt signal: upstream work the team would otherwise maintain indefinitely.
Sequencing framework and tooling upgrades. The release carries one hard constraint: PHPStan ^2.3 within the 2.x line, while PHP and Laravel requirements are unchanged. That makes it a planning input, not a routine patch. Treat it as a coupled dependency bump scheduled alongside Laravel/PHP maintenance, and use it to decide which upgrades can be deferred versus bundled.
Approving larger, riskier refactors. Better collection typing and stricter eager-loading inference reduce the chance a refactor silently changes data behavior. That is a direct argument for greenlighting modernization work — extracting services, reshaping repositories, moving to custom query builders — that would otherwise be judged too risky.
CI gate design: blocking vs. advisory. The release adds reporting for invalid eager-loading column selections combined with callbacks, such as with(['posts:id' => $callback]) — precisely the correctness-and-performance pitfall that should fail a PR rather than reach production. This supports making static analysis a blocking gate instead of a decorative check.
Standardize vs. drift across repositories. The adjacent zero-configuration wrapper (Larastan plus Rector plus Pint, with baselines and GitHub Actions integration) makes it realistic to hold one analysis profile org-wide instead of letting per-repo phpstan.neon files diverge into inconsistent gates that verify nothing.
Where this should not drive a decision. It is not a security scanner, a performance profiler, a test replacement, or a runtime safeguard. It changes nothing about production behavior, so it is not an input to availability, scaling, or incident response.
Consider adoption when:
toBase() forwarded-call fix is directly relevant.Look elsewhere or defer when:
For executives. This is a free, MIT-licensed quality gate for our Laravel services. It finds bugs without running code — wrong relationship shapes, broken eager-loading, mistyped collection keys — which are exactly the defects that reach production today because tests rarely cover them. The current release is purely additive and fix-oriented, with 6.5k+ stars and a release cadence that includes first-time contributors; it adds no new PHP or Laravel requirements, and the only action item is coordinating a PHPStan minor upgrade. It introduces no production code path, no runtime dependency, no database surface, and no container bindings: it is a require-dev line plus a CI step, reversible by reverting a lockfile. Expected return is fewer production defects and faster, safer refactors at zero licensing cost. Recurring cost is roughly one engineer-day per repository per upgrade cycle plus baseline review; the recurring risk is baseline rot, mitigated by a named owner and a standing quarterly upgrade slot. One governance item to close first: the package name, repository, and release metadata are inconsistent, so confirm the canonical package and publisher before going beyond a pilot.
For engineering. Treat this as a coupled bump: move PHPStan to ^2.3 and Larastan to ^3.13 in the same pull request, run composer update, and inspect the lockfile diff for transitive extension changes. Capture the analysis delta against the pre-upgrade run before deciding anything. What is new: relation-of<Model, Relationship> plus inferred relationship types in eager-loading arrays across with(), withOnly(), load(), and loadMissing(); opt-in PHPStan 2.3 bleeding-edge inference for empty collections and closures; corrected collection key types on concat(), merge(), shift(), and splice(); reporting of invalid eager-loading column selections combined with callbacks; a null package-manifest bootstrap fix that removes a class of stripped-CI bootstrap failures; and correct resolution of forwarded builder calls to custom query builders from toBase(). Triage the delta into three buckets — genuine bugs surfaced, false positives to baseline with a documented reason, pre-existing debt for the backlog — and regenerate the baseline only after triage, so it records decisions rather than masking them. If the repo uses custom Eloquent query builders or toBase() overrides, validate those classes explicitly; if it uses eager-loading column selection with callbacks, expect that reporting to be the largest source of new failures. Do not enable bleeding-edge inference in the blocking gate initially — evaluate it in a non-blocking job. Sequence as a one-repo pilot, then a templated rollout with a shared phpstan.neon, then leverage relation-of in the highest-value signatures: query builder returns, repository methods, and scopes. Two caveats to keep visible: the wrapper and the engine have different owners and cadences, so standardize on one of them deliberately rather than mixing; and zero-configuration defaults are an adoption asset but a scaling liability, because the first custom rule or targeted suppression puts you into PHPStan configuration anyway, and those opinions must be reconciled with team policy rather than quietly overridden.
How can I help you explore Laravel packages today?