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

Attributes Laravel Package

php-static-analysis/attributes

PHP attributes that let you annotate classes, methods, and properties with metadata for static analysis tools, improving type inference, purity checks, and IDE support. Lightweight, framework-agnostic, and easy to drop into existing codebases.

Deep Wiki
Context7

Getting Started

composer require --dev php-static-analysis/attributes

Install it as a dev dependency: the attributes are metadata for analyzers, not runtime behavior, so most projects do not need them in production require. If you are publishing a library whose public API uses these attributes, install them in require instead and keep the constraint loose, or consumers may not be able to autoload the attribute classes.

Where to look first:

  1. src/ — the attribute class list is the actual API surface. This package is small; the value is knowing exactly which attribute names exist and what each one is intended to signal.
  2. README.md — check the support matrix. A common issue with attribute packages is that the attribute is provided here but only consumed by a specific analyzer version (or only by a plugin). Do not assume PHPStan, Psalm, and PhpStorm all honor the same set.
  3. Your existing docblocks — the fastest migration target is replacing annotations you already rely on, e.g. /** @pure */ → #[Pure] on a method, or /** @internal */ → #[Internal] on a class.

First use case: annotate a stateless utility method as #[Pure] and a value object as #[Immutable], then run PHPStan/Psalm at your current level and confirm the analyzer actually changes its inference. If output does not change, the attribute is not wired into your toolchain yet — fix that before rolling it out.

Implementation Patterns

Annotate at the narrowest scope. Put #[Pure] on individual methods rather than whole classes unless every method qualifies. Same for #[Internal] — class-level is fine for a whole implementation namespace, method-level is better for mixed public APIs.

Replace, don't duplicate. If the analyzer already understands the docblock equivalent, do not keep both. Pick attributes as the canonical form, and update code review rules so contributors don't reintroduce @pure/@internal docblocks that silently drift.

Use it as an API contract.

  • #[Pure] / #[NoReturn] on factory and guard methods so the analyzer can reason about control flow.
  • #[Immutable] / #[ReadOnly] on DTOs and value objects to prevent accidental mutation in calling code.
  • #[Internal] on classes outside your supported public API, then enforce with a rule that flags cross-package usage.
  • #[Deprecated] on public methods before removal; combine with phpstan-deprecation-rules if available in your stack so internal call sites fail CI.

Suppress narrowly. If the package exposes a suppression attribute, prefer it over inline @phpstan-ignore-line / @psalm-suppress because it keeps suppression metadata discoverable and greppable. Always include the specific identifier and a reason: a suppression without a code and a comment is the same as disabling the rule.

Layer with existing extensions. Use the attributes to express intent, and reach for first-party extensions for types. Attributes cannot express generics or template bounds; keep @template, @param, and @return docblocks for that and use attributes only for purity, immutability, deprecation, and visibility hints.

CI pattern. Pin the analyzer and this package together. Add a job that runs PHPStan/Psalm at a fixed level so attribute changes are validated continuously; otherwise a version bump to the attributes package can change analyzer results without any code change in your repo.

Migration pattern. Convert one module at a time, run the analyzer, and diff the reported errors. Attributes are declarations; if converting a docblock to an attribute removes an error, the analyzer was reading it — if it does not, it wasn't.

Gotchas and Tips

  • Attributes do nothing at runtime. They are inert metadata. If you are not running a static analyzer that reads them, adding them changes nothing. Verify with reflection: (new ReflectionMethod(Foo::class, 'bar'))->getAttributes() should return the attribute, and the class must be autoloadable for it to instantiate.
  • Analyzer support is not uniform. Confirm per tool. Some attributes are understood natively by one analyzer and ignored by another; others require a custom extension or a minimum version. Check the README support matrix and test in your actual CI environment, not just the IDE.
  • #[Pure] is a promise, not a check. If you mark a method pure that reads a global or mutates state, the analyzer will trust you and produce false negatives. Wrong annotations are worse than none — they hide bugs. Keep purity annotations close to review and add a test that exercises the method.
  • #[Immutable] semantics vary between tools. One analyzer may treat it as "no public setters," another as "all properties readonly." Read the definition your analyzer uses before annotating aggregate objects with nested mutable state.
  • Dev dependency leakage. If the attribute classes are require-dev but your shipping code references them, consumers get "class not found" errors the moment reflection touches the class. Either move to require or keep attributes strictly in code paths only your own toolchain scans.
  • Autoloading and classmap issues. Attributes fail silently in static analysis if the class cannot be resolved. Run composer dump-autoload -o and verify with composer why php-static-analysis/attributes that exactly one version is installed.
  • Suppression rot. Suppression attributes survive refactors and mask new issues. Add a code owner for suppression changes and periodically audit them. When you upgrade the analyzer, re-check each suppression.
  • Version pinning. A patch release of either the attributes package or the analyzer can change reported results. Pin both in composer.json and upgrade deliberately, reviewing the CI diff.
  • Extension points. If the built-in attribute set is missing something you need (e.g. a domain-specific purity hint), do not abuse an existing attribute — write a custom PHPStan TypeSpecifier/DynamicMethodReturnTypeExtension or a Psalm handler that reads your own attribute. That keeps semantics honest and lets the analyzer do real reasoning rather than trusting a misused marker.
  • PHP version floor. Attributes need PHP 8.0+; readonly-related annotations may require 8.1+. Check composer.json before adopting if you support older runtimes in libraries.
  • Debugging checklist: (1) does reflection see the attribute, (2) does the analyzer version support it, (3) is the class autoloaded in the analyzer's bootstrap, (4) does removing it change the analysis output? If (4) is "no," it is not working, regardless of what the docs say.
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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons