super-kernel / annotator
Restores and queries build-generated, package-aware PHP attribute records for SuperKernel.
Requires
- php: >=8.4.27 <8.5
- super-kernel/contract: 1.0.0-alpha.2
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.95.27
- phpunit/phpunit: ^13.4.5
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-11-11 02:22:10 UTC
README
English | 中文文档
SuperKernel Annotator
super-kernel/annotator restores the native PHP Attributes that skernel build collects from a project and its installed packages, and answers queries about them without scanning sources or loading the annotated classes.
Installation
composer require super-kernel/annotator
The package has no requirement beyond PHP. The records it restores exist only after skernel build has run in the project. super-kernel/di restores them when it creates the root container; without a container, the providers of super-kernel/metadata supply what restoration needs.
What it provides
- An immutable collector that finds the classes and methods carrying an Attribute, by its exact class or by a parent class or interface.
- The Attributes declared on one class, method, or property, as instances that were constructed and validated at build time.
- The skipped-class diagnostics of the build: the classes whose Attributes
skernel buildcould not collect. - Restoration of the records generated by
skernel build, rejecting records that do not match the installed packages. - A publisher that build tools use to write the records.
It does not:
- scan class files, construct Attributes from source, or decide which classes are collected;
skernel builddoes; - read DocBlock annotations; it covers native PHP Attributes only;
- load or reflect the annotated classes when it answers a query;
- print the skipped-class diagnostics when an application starts.
Quick start
In an application created from super-kernel/skeleton, declare an Attribute for routes. Save it as src/Routing/Route.php:
<?php declare(strict_types=1); namespace Src\Routing; use Attribute; #[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] final readonly class Route { public function __construct(public string $method, public string $path) { } }
Use it on a controller. Save the controller as src/Http/PageController.php:
<?php declare(strict_types=1); namespace Src\Http; use Src\Routing\Route; final class PageController { #[Route('GET', '/')] public function home(): string { return 'Home'; } #[Route('GET', '/about')] #[Route('GET', '/about-us')] public function about(): string { return 'About'; } }
Ask the collector for every method with a route. Save the script as bin/routes.php:
<?php declare(strict_types=1); use Src\Routing\Route; use SuperKernel\Context\ApplicationContext; use SuperKernel\Contract\AnnotationCollectorInterface; require dirname(__DIR__) . '/vendor/autoload.php'; $collector = ApplicationContext::getContainer()->get(AnnotationCollectorInterface::class); foreach ($collector->getMethodsWithAttribute(Route::class) as $class => $methods) { foreach ($methods as $method => $routes) { foreach ($routes as $route) { echo $route->attribute()->method, ' ', $route->attribute()->path, ' -> ', $class, '::', $method, PHP_EOL; } } }
Build the project and run the script:
skernel build php bin/routes.php
It prints:
GET /about -> Src\Http\PageController::about
GET /about-us -> Src\Http\PageController::about
GET / -> Src\Http\PageController::home
Public surface
| Name | Kind | Purpose |
|---|---|---|
SuperKernel\Contract\AnnotationCollectorInterface |
Interface | Queries the collected Attributes; a SuperKernel container supplies it. |
SuperKernel\Contract\AttributeMetadataInterface |
Interface | One collected Attribute: attribute() returns the instance, types() its class and captured parent types. |
SuperKernel\Contract\PackageAnnotationsInterface |
Interface | The class, method, and property Attributes of one package. |
SuperKernel\Contract\ScanDiagnosticsInterface |
Interface | Returns the skipped-class diagnostics of a collector or a package. |
SuperKernel\Annotator\AnnotationCollector |
Class | The collector; new AnnotationCollector($packages) creates one from package records, which is useful in tests. |
SuperKernel\Annotator\Cache\AnnotationCache |
Class | read() restores the collector from the records of skernel build. |
SuperKernel\Annotator\Cache\AnnotationPublisher |
Class | publish() writes the records; build tools call it. |
SuperKernel\Annotator\Model\AttributeMetadata |
Class | The collected Attribute that a build tool creates and publishes. |
SuperKernel\Annotator\Model\PackageAnnotations |
Class | The record of one package that a build tool creates and publishes. |
Behavior to know
- Run
skernel buildaftercomposer installorcomposer updateand after adding or changing an Attribute or an annotated class, or start withskernel run, which builds first. A changed annotated class is not detected; queries answer from the last build. read()raisesSuperKernel\Annotator\Exception\AnnotationCacheExceptionwhen a record is missing or invalid or the records belong to other package versions, for exampleThe annotation package-reference stub does not match current Composer metadata.A container reports it asSuperKernel\Metadata\Exception\BuildRequiredExceptionwith the messageThe generated annotation records cannot be restored. Run `skernel build` to generate the project metadata.- A query returns only Attributes declared on the queried class or member; inherited methods and properties are listed under the class that declares them.
- Methods of a class are listed in the order of their names; Attributes on one class or member keep their declaration order.
- A class that
skernel buildcould not collect is missing from every query; it appears in the skipped-class diagnostics.
Documentation
The developer documentation describes every query with complete examples, the diagnostics, restoration without a container, publishing records, and the generated files: SuperKernel Annotator.
License
Released under the MIT License. See LICENSE.