- How do I install spaze/phpstan-disallowed-calls in a Laravel project?
- Run composer require --dev spaze/phpstan-disallowed-calls. If you already use phpstan/extension-installer (which Larastan projects commonly do), the extension is registered automatically; otherwise add vendor/spaze/phpstan-disallowed-calls/extension.neon to the includes section of your phpstan.neon. PHPStan itself is a hard requirement, and Larastan normally brings it in already.
- Does phpstan-disallowed-calls work together with Larastan?
- Yes. It is a standard PHPStan extension, so it loads into the same phpstan.neon and the same analysis run as Larastan and adds its own rules on top of Laravel-aware type information. The two do not compete: Larastan improves type understanding of Laravel facades and models, while this package enforces usage policy such as banning dd(), env() outside config, or direct use of a vendor logger. There is no conflict in ordering, and no runtime code is involved. Just be aware the package ships Nette and Symfony rulesets but no Laravel-specific one, so you write your own rules.
- Which PHP and PHPStan versions does this extension support?
- The package supports PHP 7.4 through current PHP releases and works with both PHPStan 1.x and 2.x, which matters when different services in a fleet are at different PHPStan versions. Because rules and error identifiers can change between major releases, pin PHPStan and this extension together in composer.json and upgrade them as a pair. Watch upstream release notes for backwards-incompatible changes such as the identifier renames shipped in 4.15.0.
- How do I allow a disallowed call in a specific place, like tests or migrations?
- The package is built around re-allow directives rather than blanket exceptions, including allowInPaths, allowInMethods, allowInClassWithAttributes, allowWithParameters, allowInInstanceOf, allowInTypeHintPositions, and the allowExcept family. That lets you ban a function globally while permitting it in tests, seeders, migrations, or a single class that legitimately needs it. Without this mechanism a ban list drowns in false positives on a real codebase, so plan the allow rules as part of the ruleset design, not as an afterthought.
- What kinds of usage can it detect: functions, methods, constants, attributes?
- It detects disallowed function calls, method calls (including static calls), constants, namespace usage, attributes, variables, properties, keywords, and superglobals. Detection is AST-based, so it works without executing the code and runs as part of your normal static analysis. Anything not covered by a rule you configured stays invisible, so the coverage you get equals the rule surface you actually define.
- Is phpstan-disallowed-calls a security tool that stops malicious or obfuscated code?
- No, and the README says so explicitly. Because analysis is AST-based, indirect invocations such as call_user_func, variable function names, variable class names, and obfuscation will evade it. Frame it as another pair of eyes on your own mistakes and never as a compliance or hardening guarantee. If someone asks whether it stops a given attack, the honest answer is that it catches the obvious version of it.
- Do error identifiers change between versions, and how do I handle baselines?
- Yes, identifiers and messages have been renamed in releases such as 4.15.0 for static calls, extends and implements, interfaces, traits, and enums, so any ignoreErrors block or PHPStan baseline referencing the old identifiers can silently stop matching. Treat upgrades as a small migration with a documented procedure: bump the version, run analysis, and diff the resulting errors before merging. Also beware that a large legacy baseline turns an enforcement gate into a decorative one, so pair any baseline with an explicit ratchet and burn-down commitment.
- How is this different from Pint, PHPCS, or Larastan?
- They are separate gates: Pint and PHPCS handle code style, Larastan handles type correctness and Laravel-aware static analysis, and this package handles usage policy such as which logger, which HTTP client, or no var_dump. Running all three is normal in a mature Laravel pipeline and they do not duplicate each other. This one is a dev-only Composer package with no runtime dependency, so a broken rule can never affect production behaviour.
- Are there bundled configuration files I can start from?
- Yes, the docs list bundled configuration files you can include as a baseline, and the maintainers also ship Nette- and Symfony-specific rulesets. There is no Laravel ruleset, so the practical work is writing and owning your own NEON rules: for example env() outside config, dd/dump/var_dump, DB::raw without bindings, Model::unguard, and facade-versus-injection policy. A bundled generator can also convert PHP's disable_functions and disable_classes settings into disallowed rules, which is a quick way to seed an initial list.
- Who maintains this package, and is it risky to depend on?
- It is a single-maintainer package under the MIT license with a modest star count, so bus factor is a real consideration rather than a hypothetical one. The mitigating factors are that it is dev-only, the API surface is small and forkable, and the release history is dense and well tested. Pin the version, treat it as an internal capability with an owner, and store your Laravel ruleset in a shared internal package instead of duplicating NEON files across repositories.