php-static-analysis/psalm-plugin
A Psalm plugin for PHP static analysis that extends Psalm with additional checks and integrations, helping teams catch issues earlier and enforce consistent code quality in their projects.
Architecture fit. The package operates in the PHP 8 attribute-discovery space: it reflects over classes/methods/properties, reads attribute instances, and (as of 0.5.0) persists the attribute parameters alongside the discovered metadata so downstream consumers can read argument values without re-invoking reflection. This is a sensible fit for Laravel applications that use attributes for declarative configuration (routing, validation, authorization, model behavior) and want that metadata available cheaply at runtime — e.g. during service-provider boot, container resolution, or request handling. It slots into the same conceptual layer as Laravel's own discovery/caching mechanisms (event:cache, route:cache, package manifest), which is a familiar mental model for the team.
Integration feasibility. Low-to-moderate. Adoption is presumably a Composer require plus, at most, a service-provider registration and a publishable config. There is no legacy surface to reconcile because this is a greenfield evaluation. The real feasibility question is not "can we install it" but "does its discovery/storage lifecycle match ours" — specifically whether parameter storage is populated by an artisan command, lazily on first access, or during container boot, and how invalidation is triggered.
Technical risk. The dominant risk is version maturity: 0.5.0 is pre-1.0, so minor bumps may carry breaking changes to public APIs and to the on-disk/cache representation. Second is serialization fidelity — storing arbitrary attribute parameters means serializing enums, nested objects, constants, and class-string references; anything non-trivially serializable becomes a runtime failure that only appears for specific attributes. Third is staleness: cached parameters that diverge from code after a deploy produce bugs that are invisible in local development and intermittent in production. Fourth is memory/cache growth — "all parameters" for all discovered attributes can be materially larger than storing only class names.
Key questions.
config:cache / optimize?Stack fit. Assumes Laravel 10/11 on PHP 8.1+, which is the baseline for serious attribute usage. The package is complementary to — not a replacement for — Laravel's built-in route and event caching; confirm there is no overlap that would cause two competing discovery passes at boot.
Migration path. Greenfield: no prior assessment and no incumbent implementation to displace. Sequence as (1) a time-boxed spike in a non-production branch against a representative set of the attributes we actually intend to discover, including at least one enum and one object parameter; (2) an internal wrapper (a small AttributeRegistry-style interface) so application code never touches the package API directly; (3) pilot in one bounded subsystem; (4) broader rollout only after the wrapper has survived one dependency bump.
Compatibility. Verify Composer constraints against our PHP floor and Laravel minor. Check behavior under config:cache and route:cache, since cached config can freeze discovery settings in ways that surprise teams. Confirm the package does not require a specific cache driver we don't run in production.
Sequencing. Do not adopt before the wrapper exists — that is the single decision that converts a 0.x dependency from a liability into a contained one. Defer any use in hot paths until a benchmark shows the parameter store actually beats direct reflection for our access patterns; for a handful of attributes read once per request, reflection may be cheap enough that the cache adds risk without benefit.
Maintenance. Pre-1.0 cadence means every minor release needs a read of the changelog before merge. Assign a named owner. Budget for occasional small refactors inside the wrapper rather than across the codebase.
Support. Determine whether this is vendor-backed or a single-maintainer package; the answer changes our tolerance for adopting it in a critical path. Check open-issue responsiveness and whether security issues have a disclosure path.
Scaling. Parameter storage scales with the number of attributes discovered, not with request volume, so the cost is a fixed memory/cache-size increase per process — acceptable in most apps but worth measuring if discovery covers a large domain model. Multi-node deployments require the store to be either per-node-regenerated or shared-and-invalidated; a stale shared cache is the most likely scaling failure.
Failure modes. (1) Stale parameters after deploy — silently wrong behavior, hardest to detect; mitigate with deploy-time cache clear in the release script. (2) Serialization failure on an exotic attribute parameter — loud, surfaces at discovery time, caught by CI if discovery runs in tests. (3) Missing attribute due to autoload/classmap drift after composer dump-autoload. (4) Silent divergence between reflected and stored values if the package falls back to reflection on cache miss — confirm whether it fails closed or open.
Ramp-up. Low for anyone fluent in Laravel discovery patterns; the concept is one sentence. The learning cost sits in the operational rules — when to rebuild the store, what cannot be stored, and why the wrapper exists — which should be a short written runbook rather than tribal knowledge. Estimate half a day for a mid-level engineer to be productive, plus the spike above.
How can I help you explore Laravel packages today?