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

Annotations Laravel Package

laravelcollective/annotations

LaravelCollective Annotations brings Doctrine-style annotations to Laravel, letting you define routes, middleware, and event listeners directly in controller classes. It scans annotated methods to register routes and hooks, keeping configuration close to your code and reducing clutter in route files...

View on GitHub
Deep Wiki
Context7

Getting Started

This release adds first-class PHP 8 attribute support on top of the existing annotation system, so the fastest path is to convert one existing annotated class and confirm it behaves identically before rolling out further.

  1. Check your PHP floor first. The package still installs on PHP 7, but attributes are only read on PHP 8. If any environment in your matrix (CI, a legacy staging box, a queue worker image) is on 7.x, attributes in that environment are parsed as comments and silently ignored — see Gotchas.
  2. Update and read the upgrade note. v8.1 is backwards compatible at the API level, but the namespaces used by custom annotations have moved. If you have written your own annotation classes, this is the only step that requires code changes.
  3. Find your existing annotations. Grep for the old namespace or the annotation docblock syntax across app/ — typically controllers, form requests, models, and console commands. That list is your migration backlog, ordered by risk.
  4. Convert one class. Replace the docblock annotation with the equivalent attribute on the same class or method, run the feature's tests, and diff behaviour. Attribute discovery goes through the same reflection pass, so the result should be a no-op functionally.
  5. First real use case: take a controller with a handful of route annotations and move it to attributes. It is the lowest-blast-radius conversion, produces an immediately visible diff, and validates that discovery, caching, and route registration all still work in your setup.

Where to look first: the upgrade guide for the namespace mapping, then the attribute class definitions shipped with the package (they document the valid targets and constructor signatures, which is far more reliable than the README for edge cases).

Implementation Patterns

Strangler migration, one class at a time. Because both syntaxes are supported in v8.1, you can convert incrementally rather than in a big-bang PR. Keep a rule that a given class uses one style or the other — never both on the same method — so reviewers can reason about a diff without cross-referencing two syntaxes.

Mirror the annotation as an attribute, not a rewrite. Attributes take the same arguments as the annotation they replace, but as real PHP values: named arguments instead of key="value" strings, class constants and ::class instead of string literals. Resist the urge to refactor while converting; do the syntactic move in one commit and any behavioural change in a separate one.

Wrap the package's attributes in your own where you repeat yourself. If you find yourself writing the same attribute with the same arguments across dozens of classes, subclassing or composing your own attribute gives you a single place to change defaults later — and insulates most of your codebase from the next namespace reshuffle.

Register discovery in a service provider, not ad hoc. Anything that scans for attributes should be booted once, in a dedicated provider, so the reflection cost is paid in one predictable place and is easy to trace when something unexpectedly stops being discovered. This also gives you a natural spot to add a cache warm-up.

Pair with static analysis. Add a PHPStan/Psalm rule or a simple architecture test that asserts attribute usage matches your conventions (correct target, required arguments). Attributes fail at reflection time, not parse time, so without static checks a typo surfaces at runtime — often in production, on a route nobody hit in staging.

Test the discovery, not just the handler. For each converted class, assert the attribute is actually picked up (route registered, binding resolved, listener attached) rather than only that the method works when called directly. The failure mode here is a class that runs fine but is never wired up.

Gotchas and Tips

Silent no-ops on PHP 7. #[Foo] is a comment to a PHP 7 parser. Nothing errors; the attribute is simply never seen. If your CI runs 7.x while production runs 8.x (or vice versa), you can ship a change that passes everywhere and does nothing in one place. Gate attribute-only code behind an explicit PHP version check, or drop 7.x from the matrix so the discrepancy can't exist.

The namespace change is the breaking part. Custom annotations must be updated to the new namespaces. This is not caught by the parser — the class simply won't be found, and depending on the package's error handling you may get a confusing "annotation not recognised" or, worse, silence. Do this upgrade in its own commit with no other changes so a bisect lands on it cleanly.

Clear every cache after converting. Attribute and annotation metadata is typically cached (and often compiled). route:cache, config:cache, view:cache, and the package's own discovery cache all need clearing; stale caches are the most common cause of "I converted it and nothing changed." In local dev, disable the discovery cache entirely so edits take effect without a manual flush.

Attribute targets are enforced at reflection time. #[\Attribute(\Attribute::TARGET_METHOD)] means the same attribute on a class throws rather than being ignored. When converting an annotation that didn't declare a target (annotations are permissive), add the right target flag deliberately — otherwise a copy-paste onto the wrong element becomes a runtime exception instead of a no-op.

Repeatable attributes behave differently from repeated annotations. If the original annotation allowed multiple instances, the new attribute class must be declared IS_REPEATABLE. Missing this flag produces a fatal error on the second occurrence — and it will be the one class in your codebase that used the annotation twice.

Beware constructor promotion and named arguments. Attributes use constructor promotion, so argument order and names matter. Renaming an attribute's constructor parameter later is a breaking change for every call site, and because it's userland PHP it won't show up in a semver-compliant diff of the package. Treat your own attribute classes as public API.

IDE and tooling lag. Some editors and older static analysers still mangle #[...] or fail to resolve attribute classes for go-to-definition. If your team relies on docblock annotations for IDE hints, keeping the docblock alongside the attribute (harmless duplication) is a reasonable interim trade-off.

Extension point: if the package exposes a resolver or driver, that's where to hook cross-cutting behaviour — for example, logging every attribute-discovered route at boot, or applying a naming convention to all discovered classes. Doing it in the resolver keeps it out of dozens of attribute declarations.

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.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo