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.
var_dump()", "always go through our logger", "don't touch $_REQUEST", "no eval/extract") into automated CI gates via PHPStan. That converts a policy document into a build-breaking check, which is the single cheapest lever a PM has for raising quality without adding headcount or process.else, goto, declare), superglobals, and PHP's own disable_functions / disable_classes lists. That is a broad, config-driven surface area for a composer require --dev.allowInTypeHintPositions option let you forbid direct use of a legacy namespace or class while grandfathering type declarations — a practical way to draw a boundary around a module you intend to strangle, and to track how much code still reaches across it.dangerous bundled config flags things like phpinfo() (which can leak session IDs) and shell-execution functions. This is scope you can put on a security workstream and demo, rather than a vague "reduce risk" line item.allowInPaths, allowInMethods, allowInInstanceOf, allowInClassWithAttributes, parameter/flag conditions) express institutional knowledge: "only the Sanitizer class may call htmlspecialchars directly." That encodes architecture decisions in config rather than in tribal memory, and makes exceptions reviewable in a PR.Adopt when most of the following hold:
instanceof, attributes on classes/methods, and type-hint positions. If your policy is just "ban these five functions globally," a simpler banned-code rule gets you 90% there with less config surface.allowExceptIn* stops evaluation of later directives; a config entry replaces prior entries for the same item) have real learning curve. Plan for a named owner, not a fire-and-forget install.Look elsewhere or de-scope when:
call_user_func-style indirection will have gaps — accept that as a known limitation in your threat model.composer.json. The "no other rules" custom-ruleset mode makes this viable, but weigh it against a manual grep for a one-time job.Watch items to flag before committing: 0 dependents on record despite 346 stars — popularity is real but downstream adoption is thin, so you are an early-ish adopter in dependency terms; MIT license is fine for commercial use; case-insensitivity is inconsistent by design (function/method/class/namespace names ignore case; constants, files, paths do not) which will confuse rule authors; error identifiers and config-schema validation changed in v3.0.0 with possible BC breaks, so pin versions and read changelogs before minor bumps.
For executives — one slide:
We can make a category of code-review comments disappear from our process at essentially zero cost. This is a free (MIT), actively maintained PHPStan add-on that fails the build when someone uses a function, class, or language feature we've decided we don't want. It is a
composer require --dev, one config file, no runtime dependency, no production code change, no vendor lock-in. It converts rules we already agree on — no debug output, only our logger, no raw superglobals, no deprecated namespaces — from "please remember" into "CI says no." It also gives us a clean, measurable way to wall off legacy code during the migration. Recommendation: adopt for the next sprint as a CI gate, scoped to 5–10 rules with a named owner.
For engineering leadership — the argument in three points:
instanceof directives mean we can say "only the Sanitizer may call this" — architecture captured in version-controlled config and diffable in code review, instead of in a wiki page nobody reads.For the engineering team — the honest caveats:
Ask: two engineer-days over one sprint — half a day to install and adopt bundled configs, one day to codify our top rules and exceptions, half a day to clear baseline findings — plus a named owner and a place in the definition of done. Success metric: reduction in repeated review comments of the "please remove var_dump / use our logger" class, and a stable rule count that stops growing after the first month (growth after that means the rules, not the code, need revisiting).
How can I help you explore Laravel packages today?