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 Frankenphp Laravel Package

nowo-tech/phpstan-frankenphp

PHPStan support for FrankenPHP projects. Ships stubs and rules covering frankenphp_* functions, worker-mode globals and runtime constants, so static analysis understands your FrankenPHP app and flags type errors early. Install with Composer and register the extension in phpstan.neon.

View on GitHub
Deep Wiki
Context7

Getting Started

Install as a dev dependency, alongside PHPStan itself.

composer require --dev nowo-tech/phpstan-frankenphp phpstan/phpstan

The package ships PHPStan rules, not a runtime library — nothing goes into production. Keep it in require-dev and make sure your CI image installs dev dependencies for the analysis job (a common first stumble when the rules vanish in CI).

Find the rule sets before writing config. The value of this package is that rules are split by migration level, so the first thing to do is inspect what you actually got:

ls vendor/nowo-tech/phpstan-frankenphp
find vendor/nowo-tech/phpstan-frankenphp -name '*.neon'

You are looking for the include files (typically one per level — something like a "classic" set for PHP-FPM → FrankenPHP classic, and a stricter "worker" set for classic → worker mode) plus a demos/ or docs/ folder with a before/after case for every rule. Read the demos first. With a zero-star package there is no blog-post ecosystem to lean on; the demos are the documentation.

Wire it up incrementally, one level at a time:

# phpstan.neon
includes:
    - vendor/phpstan/phpstan/conf/bleedingEdge.neon
    - vendor/nowo-tech/phpstan-frankenphp/rules-classic.neon
    # - vendor/nowo-tech/phpstan-frankenphp/rules-worker.neon   # add later

parameters:
    level: 6
    paths:
        - src
        - public

Use the exact filenames present in the vendor directory — do not copy include paths from the README of a different version.

First use case: run only the classic level against a single directory that is closest to the entrypoint (public/, your front controller, bootstrap files). That is where FPM-specific assumptions live — fastcgi_finish_request(), apache_* calls, $_SERVER['REQUEST_URI'] parsing, header()/exit control flow. Get that green, then enable the worker rules, which are the ones that actually hurt: leaked request state, static caches, singletons holding per-request data.

vendor/bin/phpstan analyse public src --memory-limit=1G

Implementation Patterns

Treat the two levels as two separate gates. Classic-level violations block the "switch the SAPI" milestone. Worker-level violations block the "flip to worker mode" milestone. Run them as two config files so a team can be green on one and red on the other without ambiguity:

vendor/bin/phpstan analyse -c phpstan-classic.neon src
vendor/bin/phpstan analyse -c phpstan-worker.neon src

This also lets you put the worker gate in a non-blocking CI job first (continue-on-error: true) and flip it to blocking when the count reaches zero.

Adopt via baseline, but baseline per level. Generate the classic baseline, fix what's cheap, then generate the worker baseline separately. Never share one baseline file across both levels — regenerating it after enabling worker rules will silently absorb new violations.

parameters:
    reportUnmatchedIgnoredErrors: true
    ignoreErrors:
        - identifier: nowo.frankenphp.worker.superglobal   # illustrative — take the real identifier from the output
          path: src/Legacy/*

Prefer identifier: over message matching. Messages get reworded between releases; identifiers are the stable contract, and you get them from --error-format=table or --error-format=json.

Pair the analysis with a real refactor pattern. The rules will relentlessly point at superglobals and statics, so standardise the fix early or every developer invents their own:

  • Introduce a small RequestContext value object populated once at the worker entrypoint; inject it instead of reading $_SERVER/$_GET deep in the call stack. This collapses dozens of violations into one place you can safely ignore.
  • Reset stateful services between requests: clear static caches, CachedReader-style memoizers, registry singletons, and any container-bound object that stores the current user/request. Implement a reset() interface and call it from the worker loop.
  • Make bootstrapping idempotent — no side effects at include time, no define() of request-scoped values.

GrumPHP / pre-commit hook, scoped so it stays fast:

# grumphp.yml (excerpt)
tasks:
  phpstan:
    configuration: phpstan-worker.neon
    triggered_by: [php]
    memory_limit: 1G

Directory-scoped rollout. Rules apply to paths, so you can enable the worker set only for freshly written namespaces while legacy code stays on classic:

parameters:
    paths:
        - src/Http
        - src/Worker

Use the demos as a review checklist. Each demo is a minimal reproduction of a failure mode. When a developer says "but my static $cache is fine", link the matching demo — it's more persuasive than the rule message and it doubles as a test case they can copy.

Gotchas and Tips

  • Static analysis cannot see dynamic dispatch. $fn = 'exit';, call_user_func, reflection-built services, string class names in config, and framework magic will slip past the rules. Green means "no detected FPM assumptions", not "worker-safe".

  • Superglobal rules are noisy in framework code. Symfony/Laravel bundles legitimately touch $_SERVER in one or two bootstrap files. Fix by excludePaths or a path-scoped ignore rather than disabling the rule globally — the rule is the whole point of the package.

  • CLI-only and test code will false-positive. exit in a console command, set_time_limit in a worker script, header() in a test helper. Split paths or maintain a dedicated phpstan-cli.neon include set.

  • Clear the result cache after editing includes. PHPStan caches aggressively; a changed includes: block with a warm cache can look like the new rules "did nothing":

    vendor/bin/phpstan clear-result-cache
    vendor/bin/phpstan analyse --debug src   # if still suspicious
    
  • Pin the version. Zero dependents and no ecosystem means a minor bump can rename include files or rule identifiers. Use an exact constraint ("nowo-tech/phpstan-frankenphp": "1.2.3") and bump deliberately — then re-run --generate-baseline and diff the baseline to see what changed.

  • Watch PHPStan/PHP version constraints. Rule sets written against bleeding-edge PHPStan often use RuleErrorBuilder identifiers and node types that older PHPStan doesn't expose. If composer require resolves an old PHPStan, expect fatal errors loading the rules rather than clean failures.

  • Identifiers over messages, always. When a message is reworded in a patch release, message-based ignores stop matching and CI turns red for no code change; identifier-based ignores survive.

  • Extension point: the rules themselves are ordinary PHPStan rules registered as services. If you need a project-specific variant (e.g. "only this superglobal is allowed"), register your own rule in phpstan.neon under services: and reuse the package's node-type helpers — cheaper than forking.

  • A passing run is not a migration. Validate with an actual long-running worker process: fire a few hundred requests, watch memory (leaks from static caches), and assert that user A's data never appears in user B's response. State-leak bugs are exactly what static analysis can't prove absent.

  • No dependents, no issue tracker history to mine. When a rule is wrong for your codebase, reproduce it in an isolated file first and check the demo suite — if the demo matches your code shape, it's likely a genuine finding, not a bug.

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