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

bfg/attributes

bfg/attributes brings PHP 8 attributes to Laravel, giving you a clean, declarative way to configure models, controllers, and services. Reduce boilerplate and keep metadata close to your code with simple, reusable attributes.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Install with composer require bfg/attributes. Check composer.json first — you need PHP 8.0+ (8.1+ realistically for readonly/enums in attributes) and a Laravel version that supports package auto-discovery.
  • Look here first: src/ for the attribute classes and whatever helper reads them (commonly a Reader, Resolver, Attributes facade, or a trait). With 0 stars and 0 dependents the README will likely be thin, so treat the source as the documentation. Confirm whether it ships a service provider (extra.laravel.providers) or is purely a static utility.
  • Sanity-check before designing around it. Spike it in tinker:
$ref = new ReflectionClass(App\Models\Post::class);

foreach ($ref->getAttributes() as $attribute) {
    dump($attribute->getName(), $attribute->getArguments());
}

If that works natively, the package is only worth adopting for the convenience layer it adds on top — so verify what that layer actually buys you (caching? attribute inheritance? a discovery registry?).

  • First real use case: declarative metadata on a class that you'd otherwise put in a config array or a const. E.g. tagging a model, job, or exporter with #[SlugSource('title')] or #[Retry(3)] and reading it at boot time rather than hard-coding a switch.

Because the package is essentially unproven (0 stars, 0 dependents, score 0.03), do the spike before you let it into a shared codebase, and keep the call sites behind your own thin wrapper.

Implementation Patterns

Declare attributes, don't consume them inline. Define your attribute classes under app/Attributes/ with explicit targets and flags — this is plain PHP 8 and does not depend on the package:

#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
final class Feature
{
    public function __construct(public string $flag) {}
}

Then use the package's reader (or a small helper of your own) as the single entry point for resolution.

Boot-time discovery in a service provider. The most valuable day-to-day pattern: scan a directory of classes once, read their attributes, and register bindings/tags. Do this in register() or a dedicated AttributeServiceProvider and cache the result — never reflect on every request.

foreach (File::allFiles(app_path('Services')) as $file) {
    $class = /* resolve FQCN from path */;

    foreach ((new ReflectionClass($class))->getAttributes(Feature::class) as $attr) {
        $this->app->tag($class, 'feature:'.$attr->newInstance()->flag);
    }
}

Use attributes as declarative config for your own abstractions. A strong pattern is an interface + attribute pair: the interface defines behavior, the attribute carries the parameters (#[RateLimit(60)], #[Cacheable(ttl: 300)]). Your resolver reads the attribute and hands off to the concrete implementation. This keeps the package at the edges of your code rather than tangled through it.

Bridge to the container lazily. Resolve and instantiate attributes only for classes you actually touch (getAttributes() + newInstance()), not for the whole app. Attribute constructors run on newInstance(), so keep them side-effect free — an attribute constructor that does I/O will surprise you.

Wrap it. Given the maturity level, put a single AttributeResolver service in front of the package. If you later swap to raw reflection or a maintained alternative, one class changes instead of fifty.

Test through reflection. Tests are straightforward — assert on the resolver output rather than on attribute instances:

$meta = app(AttributeResolver::class)->for(ExportJob::class);
$this->assertSame('csv', $meta->format);

Gotchas and Tips

  • Maturity is the headline risk. 0 stars, 0 dependents, score 0.03 means no community validation, no issue backlog to learn from, and no guarantee of PHP/Laravel version bumps. Pin the version in composer.json and budget for forking it — the underlying PHP 8 reflection API is stable, so a fork is cheap.
  • Class attributes are not inherited by default. ReflectionClass::getAttributes() on a subclass returns only the subclass's own attributes. Use getAttributes(Base::class, ReflectionAttribute::IS_INSTANCEOF) when you need to match subclasses of an attribute, and walk getParentClass() yourself if you want inheritance semantics. This is the #1 source of "why is my attribute not firing" bugs.
  • getAttributes() returns ReflectionAttribute, not your class. You must call newInstance() (or getArguments()), and you must pass the FQCN or an IS_INSTANCEOF flag — passing a short name silently returns an empty array.
  • Attribute arguments must be constant expressions. No config(), no env(), no now() inside #[...]. If you need runtime values, store a config key string and resolve it later in your reader.
  • Attribute::TARGET_* and IS_REPEATABLE matter. Omitting the target makes the attribute legal everywhere, which hides mistakes; omitting IS_REPEATABLE makes a second application a fatal error. Set both explicitly.
  • Cache reflection in production. Reflection is not free, and directory scans at boot are worse. Compute the map once (in a cached config or a compiled class map) and invalidate on deploy. Watch out for OPcache and opcache.validate_timestamps=0 in production masking a stale map after a hotfix.
  • Package auto-discovery: if the package registers a provider, confirm it appears in php artisan about / bootstrap/cache/packages.php. If it doesn't and you expected it to, add it manually to config/app.php — a silent no-op is a common failure mode for low-traffic packages.
  • Debugging tip: when an attribute "isn't working," dump the raw reflection first — dd((new ReflectionClass($c))->getAttributes()) — before suspecting the package. Most failures are a wrong FQCN, a missing IS_INSTANCEOF, or an attribute applied to a method/property when it's declared TARGET_CLASS.
  • Extension points are probably minimal. Don't count on events, config files, or a driver system. Design your own resolver interface so you can extend behavior without patching vendor code.
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