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

Class Metadata Laravel Package

zenstruck/class-metadata

Deep Wiki
Context7

Getting Started

zenstruck/class-metadata is framework-agnostic and ships no Laravel service provider, so "getting started" is really three steps: install it, annotate a class, and build a lookup index.

  1. composer require zenstruck/class-metadata
  2. Annotate a class with an alias/metadata attribute (PHP 8 attributes required):
use Zenstruck\ClassMetadata\Attribute\ClassAlias;

#[ClassAlias('stripe')]
final class StripeGateway { /* ... */ }
  1. Build a MetadataFactory over the directory you want scanned, pointing it at a cache file:
use Zenstruck\ClassMetadata\MetadataFactory;

$factory = MetadataFactory::create(app_path(), storage_path('app/class-metadata.php'));
$factory->for('stripe');                 // lookup by alias
$factory->for(StripeGateway::class);     // lookup by class

Look first at the attribute classes (Attribute/ClassAlias, Attribute/ClassMetadata) and MetadataFactory — those are basically the entire public surface. The first real use case in a Laravel app is a human-readable registry of "pluggable" classes (payment gateways, export formats, notification channels, workflow steps) where you store 'stripe' in the DB/config rather than a FQCN and resolve the class later.

Note: confirm exact factory method names/signatures against the README — the package is small and the API has shifted across releases.

Implementation Patterns

  • Bind as a singleton in a service provider. Construct the factory once in register()/boot() and bind it; inject where needed. Rebuilding the index per request is the main thing to avoid.
  • Compile in a deploy step, not at runtime. The package's whole value is that expensive reflection/scanning happens at build time and runtime lookup is a static array in a generated PHP file. Add a custom artisan command (php artisan class-metadata:build) and call it from your deploy script or a Composer post-autoload hook; optionally hook cache:clear.
  • Use aliases as stable persistence keys. Store 'stripe' in DB columns/config, not the class name. You get refactor freedom — rename or move the class without migrating stored values.
  • Resolve, then container-make. The factory returns a class string; pass it to app($class) so the concrete implementation gets dependency injection instead of being new'd.
  • Custom metadata for domain data. Define your own metadata attribute extending the package's base to attach structured info (label, icon, sort order, feature flag) to a class, then read it in a registry/collection.
  • Registry / enum replacement. Where you'd otherwise reach for a PHP enum or a giant match, a metadata-backed class registry scales better when each implementation has different constructor dependencies.
  • Scan narrowly. Point the factory at app/ (or specific namespaces) rather than the whole project to keep build time and the compiled file small.

Gotchas and Tips

  • No Laravel auto-wiring. No service provider, no config file, no auto-discovery — you own construction, caching, and refresh. Budget for that.
  • Stale compiled cache is the #1 bug. Add a class/alias and forget to rebuild, and lookups silently miss. Rebuild on boot/watch in local dev; make the build part of deploy and fail the deploy if it errors.
  • Opcache + generated files. If the cache file is rewritten at runtime on a long-lived PHP-FPM worker, opcache may serve the stale version — opcache_invalidate() after write, or better, only write during deploy.
  • Attributes are opt-in and not inherited. An attribute on a parent class won't appear on children unless you explicitly walk parents; also set #[Attribute(Attribute::TARGET_CLASS)] correctly on custom attributes or PHP rejects them.
  • Alias collisions. Two classes claiming 'stripe' — check whether the factory throws or last-wins, and assert uniqueness in a test.
  • Unknown lookups. Verify whether for() throws or returns null for a missing class/alias, and handle it at the boundary (validate incoming config values).
  • Small package, small bus factor. 14 stars, single maintainer, MIT. Pin the version and keep usage behind your own thin wrapper interface so swapping it out is cheap if maintenance stalls.
  • Testing. Build a factory against test fixtures (or the real app/) in setUp, and keep a test asserting every expected alias resolves to the right class.
  • Debugging. When a lookup is wrong, open the generated cache file — it's a plain PHP array and tells you exactly what was indexed and under which keys.
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.
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle