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 Banned Code Laravel Package

ekino/phpstan-banned-code

PHPStan extension that detects banned code in your project, like var_dump, exit, eval, print, shell execution, and other unwanted functions. Configure the exact nodes and functions to block, enforce rules in CI, and keep your codebase clean.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit

  • This is not an application dependency —it is a PHPStan rule set implemented as an extension. It occupies the static-analysis layer of the SDLC, sits entirely in require-dev, and ships zero code into the runtime artifact. Blast radius is therefore limited to CI and developer machines.
  • It fits any Laravel codebase that already runs PHPStan or Larastan, because Larastan is a PHPStan extension and this package composes alongside it in the same phpstan.neon config. Adoption cost is one Composer line plus a NEON block, not a new tool in the pipeline.
  • Mechanically it is a node visitor over the php-parser AST: configuration is keyed by AST node type (Expr_FuncCall, Stmt_Echo, Expr_Eval, Expr_Exit, Expr_Print, Expr_ShellExec), with a function denylist per node. That is a clean, declarative model —non-authors can review the banned list, and policy lives in version control rather than in a wiki.
  • The two product-relevant features are use_from_tests (flags use Tests\... imports in non-test files —a cheap architectural boundary that maps directly onto Laravel's test-namespace conventions) and non_ignorable: true by default, which prevents violations from being absorbed into a PHPStan baseline. The second is what turns a lint suggestion into an enforceable control.

Integration feasibility

  • Path is well-trodden: composer require --dev ekino/phpstan-banned-code; with phpstan/extension-installer present it auto-registers, otherwise add extension.neon to includes. Configuration goes under parameters.banned_code.
  • The only friction is version-pinning. v3.x targets PHPStan 2.x (v2.x → PHPStan 1.x, and so on); the extension tracks PHPStan majors 1:1. We must pin both together and treat a PHPStan upgrade as an upgrade of this package in the same change.
  • Secondary coupling to nikic/php-parser majors exists because configuration references AST node type strings. A parser major bump can rename or restructure nodes, and the failure mode is silent non-detection rather than a red build. That is the main technical risk to plan for.

Technical risk

  • Low: dev-only, MIT, no runtime surface, trivially removable.
  • Medium: upgrade lockstep with PHPStan majors; occasional false positives on legitimate constructs (echo/print in Blade-adjacent or legacy templates, exec in deployment console commands); a flat denylist has no per-directory allowlist, only multiple NEON configs.
  • Medium: scope misrepresentation. This detects call sites; it will not catch call_user_func('shell_exec', ...), variable functions, or reflection. It is one control among several and must not be presented as injection prevention.
  • Low-to-medium: project maturity signals are ambivalent —299 stars, small agency (ekino) maintainer, active CI through PHP 8.4 and a recent release, but effectively no downstream dependents and README-only documentation. Abandonment risk is real but survivable: the rule is a few hundred lines and reimplementable.

Key questions

  1. Is PHPStan (or Larastan) already a blocking gate in CI? If not, this package has no host and the real decision is "adopt PHPStan."
  2. Do we have evidence of the failure mode —debug calls, exit/die, or shell functions reaching shared branches? If not, we are buying a control without a problem statement.
  3. Do we want grandfathering or a hard stop? The non_ignorable default blocks baseline bypass; confirm that is the intended policy before rollout.
  4. Who owns the banned list as a reviewed artifact, and on what cadence?
  5. What is the PHPStan/PHP version matrix across our services, and does it match v3.x?

Integration Approach

Stack fit Assume Laravel 10/11/12 on PHP 8.2+, PHPStan 2.x and Larastan already installed for at least a subset of repos. The extension loads into the same analysis pass —no new CI stage, no new container, negligible added runtime. Where Larastan is present, resolve version constraints together; do not let Composer negotiate them independently.

Migration path

  1. Inventory (week 1). Add the dependency and a broad config in one representative repo. Run PHPStan locally and in a non-blocking CI job. Produce a violation count by rule category and by directory. This is the business case artifact.
  2. Tier the denylist. Tier 1 (adopt blocking immediately): var_dump, dd, dump, debug_backtrace, exit/die. Low debate, high signal. Tier 2 (next release): eval, shell_exec, exec, passthru, system, proc_open, phpinfo, backtick shell execution. Tier 3 (evaluate per repo): echo, print, print_r —noisy wherever templates or legacy output paths exist.
  3. Ratchet. Enable Tier 1 blocking with non_ignorable: true. Fix or explicitly grandfather existing hits via a scoped config include before flipping the gate, so the first day of enforcement is not a mass suppression event.
  4. Standardize. Publish one shared NEON fragment consumed by all PHP repos, so the definition of "acceptable" is portable across teams, contractors, and acquired codebases.

Compatibility

  • Confirm PHPStan ≥2.x, PHP 8.x, and phpstan/extension-installer (or explicit include) on every target repo; pin the extension version alongside PHPStan in composer.json.
  • Add a smoke test that intentionally introduces a var_dump in a fixture and asserts a failure, so a silent parser/node-type drift is caught by CI rather than by an incident.
  • For monorepos or directory-specific exemptions, use multiple PHPStan config files rather than disabling the rule globally.

Sequencing Dependency add → config + dry-run metrics → Tier 1 blocking → shared config rollout → Tier 2 → optional Tier 3 and use_from_tests. Tie the PHPStan-major-upgrade workstream to this package's version so both move in one PR.

Operational Impact

Maintenance Low, ongoing: the banned list is stable and changes rarely; the config diff is reviewable by non-authors. Concentration risk is a single small maintainer plus a 1:1 PHPStan-major dependency. Budget roughly a half-day per PHPStan major upgrade, and keep a fallback: reimplementing the rule in-house is a small, well-understood task if the project stalls.

Support No vendor, no SLA. Documentation is a README with a single advanced-usage example; node-type discovery ("what string do I put in type?") is the one support question developers will ask. Mitigate with an internal one-pager listing our approved node types and banned functions. The upgrade escape hatch is strong because the failure surface is contained to CI.

Scaling Config scales linearly and cheaply —it rides the existing PHPStan run, so incremental cost is a rounding error even across many repos. Policy complexity does not scale as well: the model is a flat denylist. Per-directory allowlists can be approximated with multiple NEON configs; severity levels, auto-fix, and architectural rules (dependency direction, forbidden class usage) are out of scope and require custom PHPStan rules.

Failure modes

  • Silent non-detection after a nikic/php-parser or PHPStan major upgrade —the rule stops firing and nobody notices. Highest-severity failure; mitigated by the fixture smoke test.
  • Upgrade deadlock —PHPStan upgrade blocked because the extension has not caught up, creating pressure to remove the gate entirely. Mitigate by pinning deliberately and scheduling the pair.
  • Suppression pressure —non_ignorable: true means a legitimate exec in a deployment command becomes a hard blocker. Without a directory-scoped config prepared in advance, the team will demand the feature be turned off wholesale.
  • Baseline bypass —if someone flips non_ignorable: false "temporarily," the control quietly stops being a policy. Treat that flag as governed config.
  • Overconfidence —this becomes the answer to "do we prevent shell injection?" It does not; it complements disable_functions, container hardening, and SAST/DAST but does not replace them. State this in the rollout comms.

Ramp-up An engineer already fluent in PHPStan needs 1–2 hours to wire the config and read the violation report; the only unfamiliar concept is AST node types in the NEON file. Teams new to PHPStan should sequence this after PHPStan itself is established, otherwise onboarding conflates two changes. Plan a short internal note covering our node-type choices, the tiered denylist, and the exemption process —that note, not the upstream README, will be what most of the org actually uses.

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.
unabomber/timezone
delatbabel/contacts
astritzeqiri/g-recaptcha
kevinongko/laravel-genode
developeruz/laravel-analytics
robbiep/afterthedeadline
frankkessler/incontact-laravel-oauth2-rest
jlxh/laravel-userlog
davidmgilo/timetables
qylinfly/role-permission
reflect-digital/conduit
takashato/laravel-vietqr
aitor24/laralang
kraenzle-ritter/entity-relations
dindigital/din-image
pomirleanu/image-colors
sawmainek/laravel-api-generator
delatbabel/jsonresponses
mouhamedfd/permissions-generator
eduplus/qr