I was looking for a convenient way to retrieve targets of PHP 8 attributes, so I could use them in my packages. I couldn't find any, so I wrote one that comes in the form of a Composer plugin.

composer-attribute-collector provides a zero-configuration, near zero-cost system to retrieve targets of PHP 8 attributes. In order to do that, after the autoloader has been dumped, the plugin collects attribute targets and generates a static file. Later, these targets can be retrieved through a convenient interface.

For example, with a Symfony application, the plugin would generate something like this excerpt:

<?php

// attributes.php @generated by https://github.com/olvlvl/composer-attribute-collector

namespace olvlvl\ComposerAttributeCollector;

Attributes::with(fn () => new Collection(
    targetClasses: [
        \Symfony\Component\Console\Attribute\AsCommand::class => [
            [ ['lint:yaml', 'Lint a YAML file and outputs encountered errors'], \Symfony\Component\Yaml\Command\LintCommand::class ],
            [ ['server:dump', 'Start a dump server that collects and displays dumps in a single place'], \Symfony\Component\VarDumper\Command\ServerDumpCommand::class ],
            [ ['debug:validator', 'Display validation constraints for classes'], \Symfony\Component\Validator\Command\DebugCommand::class ],
            [ ['translation:pull', 'Pull translations from a given provider.'], \Symfony\Component\Translation\Command\TranslationPullCommand::class ],

The following example demonstrates how targets and their attributes can be retrieved:

<?php

use olvlvl\ComposerAttributeCollector\Attributes;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
use Symfony\Component\Routing\Annotation\Route;

require_once 'vendor/autoload.php';
require_once 'vendor/attributes.php'; // <-- the file created by the plugin

// Find the target classes of the AsMessageHandler attribute.
foreach (Attributes::findTargetClasses(AsMessageHandler::class) as $target) {
    // $target->attribute is an instance of the specified attribute
    // with the actual data.
    var_dump($target->name, $target->attribute);
}

// Find the target methods of the Route attribute.
foreach (Attributes::findTargetMethods(Route::class) as $target) {
    var_dump($target->class, $target->name, $target->attribute);
}

// Find attributes for the ArticleController class.
$attributes = Attributes::forClass(ArticleController::class);

var_dump($attributes->classAttributes);
var_dump($attributes->methodsAttributes);

If that looks helpful to you, checkout composer-attribute-collector on GitHub.