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 Disallowed Calls Laravel Package

spaze/phpstan-disallowed-calls

PHPStan rules to detect disallowed functions, methods, constants, namespaces, attributes, variables, and properties without running code. Catch leftover debug calls like var_dump() and enforce custom logging or API usage in production.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

What this actually is. spaze/phpstan-disallowed-calls is not a Laravel package — it ships no service provider, no config publish, no runtime code. It is a PHPStan rule extension: a set of static-analysis rules plus a NEON configuration schema that flags disallowed functions, methods, constants, namespaces, attributes, keywords/control structures, superglobals, and (since 4.9.0) properties and enum properties. It belongs in the require-dev block and the CI pipeline, not in composer.json's runtime dependencies. That distinction drives everything below: the "integration" is a policy-as-code exercise, not an application change.

Architecture fit. Strong fit for any Laravel codebase already doing static analysis. Laravel shops typically run Larastan (PHPStan + Laravel-aware extensions), so this ruleset composes cleanly on top of an existing phpstan.neon. It has zero coupling to application code — no proxies, no bootstrapping, no runtime overhead — so it is trivially removable and cannot cause a production incident. The extension is intentionally not a security boundary; the README states it is "another pair of eyes" against your own mistakes and explicitly not a defense against hostile developers. A TPM should position it as a code-hygiene and standards-enforcement gate, never as a security control.

Integration feasibility. Low technical effort, moderate policy effort. Install is a one-line Composer dev requirement; phpstan/extension-installer auto-registers, or a two-line includes: block does it manually. The genuinely valuable part for a TPM is the allow-list model, which is unusually mature for a package this size: re-allow by path, by enclosing method/function, by parameter value or PHPDoc typeString, by flag, by instanceof / interface implementation, by class or method attributes, and by type-hint position. That means exceptions can be expressed at the right granularity instead of forcing a coarse global ignore, which is the usual reason these gates rot. The disallowExceptIn* family inverts the default (report when matched, allow otherwise) and short-circuits later directives — a subtlety worth documenting internally before teams write rules. Bundled configs exist for dangerous/loose calls, and a generator converts PHP's disable_functions / disable_classes into a snippet, which is genuinely useful for keeping staging/prod parity checks in sync.

Technical risk.

  • Blind spots are structural. Dynamic dispatch — $fn(), call_user_func, variable static calls, container-resolved calls — is largely outside what a PHPStan rule can see. In a Laravel codebase with heavy container and facade indirection, this is a real coverage gap. In 4.9.2, unknown functions without available reflection are deliberately not reported, which is the right trade-off (fewer false positives) but further widens the gap between "configured" and "enforced."
  • Version coupling to PHPStan. The changelog is a running ledger of PHPStan-version accommodations (constant declaring-class display names needing 2.1.38+, --prefer-lowest accidentally pulling PHPStan 2.x instead of 1.x, array_values() depending on a bleeding-edge 1.10.59 rule). This is a fast-moving host platform; every PHPStan major or minor bump is a potential support ticket. Pin both.
  • Configuration schema tightening. v3.0.0 converted extension parameters into a validated structure — good, but it means typos that were silently ignored now surface as errors, and rule ordering for the same call changed semantics. Anyone upgrading across the v2→v3 boundary should expect a short, noisy migration.
  • Bus factor. Small maintainer set, MIT, active releases. Single-maintainer risk is real but mitigated by the fact that the artifact is dev-only and swappable (ekino/phpstan-banned-code is a credible alternative with different config ergonomics).
  • Ecosystem signal anomaly. "Dependents: 0" against 346 stars and a decade of releases is almost certainly a registry/indexing artifact rather than true adoption. Verify actual usage before treating popularity as a proxy for stability; the score of 32.4 with opportunity 54.7 suggests the index itself is unsure.

Key questions to resolve before committing.

  1. What PHPStan level and Larastan version are we on today, and who owns the PHPStan upgrade cadence?
  2. Is the mandate "no new violations" or "clean the whole tree"? These produce very different scope and timeline.
  3. Which calls are policy (org-wide, e.g. dd, dump, var_dump, env() outside config/, DB::raw, Model::unguard) versus taste (better left to Pint/PHP_CodeSniffer)?
  4. Do we need Laravel-specific rules (facades, app(), resolve(), Artisan::call) that the package cannot detect statically — and if so, do we accept that gap explicitly?
  5. What is our exception process, and who approves a new allowIn* directive?
  6. Does the security team understand this is not a control, so it isn't cited in a compliance narrative?

Integration Approach

Stack fit. Laravel 10/11/12 + PHP 8.2–8.5 + PHPStan 2.x (with Larastan) + Composer + GitHub Actions is the well-trodden path; all of it is exercised by the package's own CI matrix, including PHP 8.5 e2e runs. If the team uses PHP_CodeSniffer/Pint for style, keep the boundary clean: style rules stay in Pint, usage prohibitions live here. There is no official Laravel ruleset (Nette and Symfony have one each), so we author and own our own phpstan-disallowed-calls.neon — treat that file as a first-class reviewed artifact, versioned in the repo and code-owned by the platform team.

Migration path. Land it in observe-only mode first. Add the dev dependency, include extension.neon (or rely on extension-installer), include the bundled disallowed-dangerous-calls / disallowed-loose-calls configs, and run analysis in CI with continue-on-error: true for one sprint. Collect the violation set, size it, and decide per rule whether to fix, baseline, or drop. Then flip the gate.

Compatibility. Requirements to pin explicitly: the PHPStan major/minor, the extension's minor (its release notes routinely name the PHPStan version they were tested against), and PHP minor in CI. Note the v3.0.0 BC surface — structured parameters, removal of the auto-appended "because reasons" message, rule ordering for duplicate targets, and default error identifiers (introduced in 3.4.0, which matters if you ignore by identifier rather than by message). Error identifiers are the right ignore currency; ignoring by message text will break the moment a message key changes.

Sequencing.

Phase Action Exit criterion
0 Inventory current PHPStan/Larastan setup, level, existing ignores Baseline documented
1 Install as dev dep, include bundled configs, run non-blocking Violation count known per rule
2 Triage: fix / baseline / reject rule; agree org policy list Signed-off rule catalog
3 Author custom disallowed*.neon with org rules and errorTip guidance (arrays supported since 4.8.0) Rules reviewed and merged
4 Enable as blocking gate; baseline frozen for legacy, strict for new code CI green on main
5 Add disable_functions generator output per environment Dev/prod parity check in CI
6 Quarterly rule review; re-evaluate on each PHPStan major Drift controlled

Sequence phase 5 after 4 — matching disable_functions is a nice-to-have that only pays off once the gate is trusted.

Operational Impact

Maintenance. Low-to-moderate, dev-only. No runtime surface, no migrations, no deploy risk. The real maintenance load is the configuration, not the code: every new allow-exception is a reviewed diff, and every PHPStan bump is a compatibility check. Budget roughly a half-day per PHPStan minor upgrade and one planning day per major. Pin the extension to a caret range and let Renovate/Dependabot open PRs so the changelog's PHPStan-compatibility notes get read by a human.

Support. MIT-licensed, GitHub-issues support model, strong README plus a docs/ tree covering bundled configs, custom rules, and each allow directive individually — documentation quality is the package's standout asset and materially reduces onboarding cost. No commercial SLA; if the org needs one, the fallback is vendoring a pinned fork or switching to ekino/phpstan-banned-code, both of which are cheap because nothing at runtime depends on it.

Scaling. Analysis cost scales with codebase size and rule count, but PHPStan's result cache absorbs most of it; the incremental cost of a few dozen disallowed-call rules is negligible next to the Larastan baseline. The scaling problem is organizational, not computational: in a monorepo or multi-repo estate, N repos means N copies of the NEON config drifting apart. Solve this early with a shared internal package or a reusable CI workflow that injects the canonical ruleset. Rule count also has a human ceiling — beyond roughly 40–60 prohibitions, developers stop reading the failures and start blanket-ignoring.

Failure modes.

Mode Symptom Mitigation
False positive blocks a merge Team frustration, pressure to disable the gate Rich allow directives (allowIn*, params, attributes) + errorTip telling devs the sanctioned alternative
Silent miss on dynamic calls Confidence exceeds actual coverage Document the limitation in the ADR; pair with code review and, where it matters, runtime checks
Config typo silently ineffective Rule believed active but isn't (pre-v3) or hard error (post-v3) Structured schema now validates; add a negative test that asserts a known-bad fixture fails
PHPStan upgrade breaks rules CI red after a dependency bump Pin both, upgrade deliberately, run the package's own e2e as a smoke test
Baseline rot Legacy ignore list grows unbounded Ratchet: no new entries; quarterly review with an owner
Message-based ignores break Ignores stop matching after a wording change Ignore by error identifier only (default identifiers available since 3.4.0)
Wrongly cited as a security control Compliance gap Explicit non-goal in the ADR; security review stays separate

Ramp-up. Roughly half a day for the platform engineer who owns the PHPStan config and authors the org ruleset; about fifteen minutes for an application developer, who only needs to learn three things: what the failure means, where the errorTip points, and how to request a scoped exception. The allow-list taxonomy is the only genuinely non-obvious surface — allowExceptIn* semantics and the "first matching allow directive wins" rule should be written into the internal runbook, since a misread here produces rules that quietly allow far more than intended. Net assessment: high leverage per unit of effort, best adopted as a scoped, well-documented standards gate on top of an existing PHPStan investment rather than as a standalone initiative.

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.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package