PHPackages                             quellabs/annotation-reader - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Parsing &amp; Serialization](/categories/parsing)
4. /
5. quellabs/annotation-reader

ActiveLibrary[Parsing &amp; Serialization](/categories/parsing)

quellabs/annotation-reader
==========================

A PHP annotations reader that parses, processes, and caches docblock annotations for classes, properties, and methods.

1.0.26(8mo ago)02252MITPHP

Since Apr 28Pushed 2mo ago1 watchersCompare

[ Source](https://github.com/quellabs/annotation-reader)[ Packagist](https://packagist.org/packages/quellabs/annotation-reader)[ RSS](/packages/quellabs-annotation-reader/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (8)Dependencies (2)Versions (21)Used By (2)

PHP Annotation Reader
=====================

[](#php-annotation-reader)

[![Latest Version](https://camo.githubusercontent.com/9ba8195886a5926f7ab6bbcd8482f761aec0a277a36da5c3ade55c73157584ce/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7175656c6c6162732f616e6e6f746174696f6e2d7265616465722e737667)](https://packagist.org/packages/quellabs/signal-hub)[![License](https://camo.githubusercontent.com/074b89bca64d3edc93a1db6c7e3b1636b874540ba91d66367c0e5e354c56d0ea/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e737667)](LICENSE)[![Downloads](https://camo.githubusercontent.com/406e7cd06064dac0ee46fd7e24a664d2670f0d311cc824bf0df86e65aaeb1a35/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f7175656c6c6162732f616e6e6f746174696f6e2d7265616465722e737667)](https://packagist.org/packages/quellabs/signal-hub)

A powerful PHP annotation reader for parsing, processing, and caching docblock annotations in PHP classes.

Overview
--------

[](#overview)

The AnnotationReader component provides robust parsing and caching of PHP docblock annotations, allowing you to define metadata directly within your class docblocks. This approach makes your code more self-documenting and reduces the need for separate configuration files.

Features
--------

[](#features)

- **Annotation parsing**: Parse docblock annotations for classes, properties, and methods
- **Import resolution**: Automatically resolves class imports for fully qualified annotation names
- **Class constant support**: Supports fully qualified class constants in annotation parameters (e.g., `ObjectName::class`)
- **Performance optimization**: Implements smart caching to improve performance
- **Flexible integration**: Easy to integrate with your existing projects
- **Error handling**: Graceful handling of malformed annotations
- **Collection support**: Returns immutable AnnotationCollection objects with array-like access

Installation
------------

[](#installation)

```
composer require quellabs/annotation-reader
```

Usage
-----

[](#usage)

### Basic Usage

[](#basic-usage)

```
use Quellabs\AnnotationReader\AnnotationsReader;
use Quellabs\AnnotationReader\Configuration;

// Create configuration
$config = new Configuration();
$config->setAnnotationCachePath(__DIR__ . '/cache');
$config->setUseAnnotationCache(true);

// Create annotation reader
$reader = new AnnotationsReader($config);

// Get annotations for a class
$classAnnotations = $reader->getClassAnnotations(MyClass::class);

// Get annotations for a class, filtered by a specific annotation
$classAnnotations = $reader->getClassAnnotations(MyClass::class, SomeAnnotation::class);

// Get annotations for a property
$propertyAnnotations = $reader->getPropertyAnnotations(MyClass::class, 'propertyName');

// Get annotations for a property, filtered by a specific annotation
$propertyAnnotations = $reader->getPropertyAnnotations(MyClass::class, 'propertyName', SomeAnnotation::class);

// Get annotations for a method
$methodAnnotations = $reader->getMethodAnnotations(MyClass::class, 'methodName');

// Get annotations for a method, filtered by a specific annotation
$methodAnnotations = $reader->getMethodAnnotations(MyClass::class, 'methodName', SomeAnnotation::class);
```

### Working with AnnotationCollection

[](#working-with-annotationcollection)

All annotation reader methods return an `AnnotationCollection` object that provides array-like access with a clean, flat structure:

```
$annotations = $reader->getMethodAnnotations(MyClass::class, 'myMethod');

// Array access by class name - returns first annotation of that type
$interceptor = $annotations[InterceptWith::class];

// Array access by numeric index - returns annotation at that position
$firstAnnotation = $annotations[0];
$secondAnnotation = $annotations[1];

// Iterate through all individual annotations
foreach ($annotations as $annotation) {
    // Each iteration gives you a single annotation object
}

// Get all annotations of a specific type (returns AnnotationCollection)
$allInterceptors = $annotations->all(InterceptWith::class);

// Check if multiple annotations of same type exist
if ($annotations->hasMultiple(InterceptWith::class)) {
    // Process multiple interceptors
}

// Collection methods
$count = count($annotations);
$isEmpty = $annotations->isEmpty();
$firstAnnotation = $annotations->first();
$lastAnnotation = $annotations->last();

// Filtering returns a new AnnotationCollection
$filtered = $annotations->filter(function($annotation) {
    return $annotation->isActive();
});

// Chaining operations
$activeInterceptors = $annotations
    ->all(InterceptWith::class)
    ->filter(fn($interceptor) => $interceptor->isActive());
```

### Handling Multiple Annotations

[](#handling-multiple-annotations)

When you have multiple annotations of the same type, the collection provides clean access patterns:

```
/**
 * @InterceptWith("AuthValidator")
 * @InterceptWith("LoggingInterceptor")
 * @Route("/api/users")
 */
public function getUsers() { /* ... */ }
```

```
$annotations = $reader->getMethodAnnotations(MyClass::class, 'getUsers');

// Get first InterceptWith annotation
$firstInterceptor = $annotations[InterceptWith::class];

// Get all InterceptWith annotations as a collection
$allInterceptors = $annotations->all(InterceptWith::class);

// Check for multiple InterceptWith annotations
if ($annotations->hasMultiple(InterceptWith::class)) {
    foreach ($allInterceptors as $interceptor) {
        // Process each interceptor
    }
}

// Get single Route annotation
$route = $annotations[Route::class];

// Iterate through all annotations (individual objects)
foreach ($annotations as $annotation) {
    // Gets: AuthValidator, LoggingInterceptor, Route
}
```

### Filtered Results

[](#filtered-results)

When filtering annotations, the result maintains the same clean structure:

```
// Filter by specific annotation class
$interceptors = $reader->getMethodAnnotations(MyClass::class, 'myMethod', InterceptWith::class);

// Or filter with custom logic
$activeAnnotations = $annotations->filter(fn($annotation) => $annotation->isActive());

// All results are AnnotationCollection with consistent access
$first = $interceptors[0];              // First annotation
$count = count($interceptors);          // Total count
foreach ($interceptors as $annotation) {
    // Iterate individual annotations
}

// Chain operations
$result = $annotations
    ->filter(fn($a) => $a->isActive())
    ->all(InterceptWith::class);
```

### Array Conversion Methods

[](#array-conversion-methods)

The `AnnotationCollection` provides three different methods to convert the collection to standard PHP arrays, each serving different use cases:

#### toArray() - Mixed Key Format

[](#toarray---mixed-key-format)

The `toArray()` method creates an array with hybrid indexing that provides both class-name access for the first occurrence of each annotation type and numeric indexing for duplicates:

```
/**
 * @Route("/api/users")
 * @InterceptWith("AuthValidator")
 * @InterceptWith("LoggingInterceptor")
 * @Cache(ttl=3600)
 */
public function getUsers() { /* ... */ }

$annotations = $reader->getMethodAnnotations(MyClass::class, 'getUsers');
$array = $annotations->toArray();

// Result structure:
// [
//     'App\Annotations\Route' => Route("/api/users"),
//     'App\Annotations\InterceptWith' => InterceptWith("AuthValidator"),
//     0 => InterceptWith("LoggingInterceptor"),  // Second InterceptWith uses numeric key
//     'App\Annotations\Cache' => Cache(ttl=3600)
// ]

// Access patterns:
$route = $array[Route::class];                    // First (and only) Route
$firstInterceptor = $array[InterceptWith::class]; // First InterceptWith
$secondInterceptor = $array[0];                   // Second InterceptWith
$cache = $array[Cache::class];                    // Cache annotation
```

This format is ideal when you need both convenient class-name access and want to preserve all duplicate annotations in a single array structure.

#### toIndexedArray() - Linear Format

[](#toindexedarray---linear-format)

The `toIndexedArray()` method returns a simple indexed array containing all annotations in their original order:

```
$annotations = $reader->getMethodAnnotations(MyClass::class, 'getUsers');
$array = $annotations->toIndexedArray();

// Result structure:
// [
//     0 => Route("/api/users"),
//     1 => InterceptWith("AuthValidator"),
//     2 => InterceptWith("LoggingInterceptor"),
//     3 => Cache(ttl=3600)
// ]

// Access patterns:
$firstAnnotation = $array[0];   // Route
$secondAnnotation = $array[1];  // First InterceptWith
$thirdAnnotation = $array[2];   // Second InterceptWith

// Iterate through all annotations
foreach ($array as $index => $annotation) {
    echo "Annotation {$index}: " . get_class($annotation) . "\n";
}
```

This format is perfect for sequential processing, serialization, or when you need a simple list without any special key handling.

#### toGroupedArray() - Grouped by Class

[](#togroupedarray---grouped-by-class)

The `toGroupedArray()` method organizes annotations by their class names, with each class name mapping to an array of all annotations of that type:

```
$annotations = $reader->getMethodAnnotations(MyClass::class, 'getUsers');
$array = $annotations->toGroupedArray();

// Result structure:
// [
//     'App\Annotations\Route' => [
//         0 => Route("/api/users")
//     ],
//     'App\Annotations\InterceptWith' => [
//         0 => InterceptWith("AuthValidator"),
//         1 => InterceptWith("LoggingInterceptor")
//     ],
//     'App\Annotations\Cache' => [
//         0 => Cache(ttl=3600)
//     ]
// ]

// Access patterns:
$routes = $array[Route::class];           // Array of Route annotations
$interceptors = $array[InterceptWith::class]; // Array of InterceptWith annotations

// Process all interceptors
foreach ($array[InterceptWith::class] as $interceptor) {
    // Handle each interceptor
}

// Check if specific annotation type exists
if (isset($array[Cache::class])) {
    $cacheAnnotations = $array[Cache::class];
}

// Get count of specific annotation type
$interceptorCount = count($array[InterceptWith::class] ?? []);
```

This format is excellent for processing annotations by type, configuration systems that need to handle multiple instances of the same annotation, or when building annotation-driven frameworks.

### Choosing the Right Conversion Method

[](#choosing-the-right-conversion-method)

- **Use `toArray()`** when you need convenient access to single annotations by class name but also want to preserve duplicates in the same structure
- **Use `toIndexedArray()`** for simple sequential processing, serialization, or when working with external APIs that expect indexed arrays
- **Use `toGroupedArray()`** when building systems that process annotations by type, handling multiple instances of the same annotation class, or creating configuration arrays

Annotation Format
-----------------

[](#annotation-format)

Annotations are defined in PHP docblocks using the `@` symbol followed by the annotation name and optional parameters. The annotation reader supports various parameter formats including strings, numbers, booleans, arrays, and the `::class` magic constant.

### Basic Annotations

[](#basic-annotations)

Simple annotations with string, numeric, and boolean parameters:

```
/**
 * @Table(name="products")
 * @Entity
 * @Cache(ttl=3600, enabled=true)
 */
class Product {
    /**
     * @Column(type="integer", primary=true, autoincrement=true)
     */
    private $id;

    /**
     * @Column(type="string", length=255)
     * @Validate("required")
     * @Validate("maxLength", 255)
     */
    private $name;
}
```

### Using Class Constants

[](#using-class-constants)

Annotations with `::class` magic constants for type-safe class references:

```
use App\Models\User;
use App\Services\ValidationService;
use App\Events\UserCreated;

/**
 * @Entity(repository=UserRepository::class)
 * @EventListener(event=UserCreated::class)
 */
class UserService {
    /**
     * @Inject(service=ValidationService::class)
     * @Cache(driver=RedisDriver::class)
     */
    private $validator;

    /**
     * @Transform(transformer=UserTransformer::class)
     * @Authorize(policy=UserPolicy::class)
     */
    public function getUser(int $id): User {
        // Method implementation
    }
}
```

### Supported Parameter Types

[](#supported-parameter-types)

The annotation reader supports these parameter formats:

- **Strings**: `"value"` or `'value'`
- **Numbers**: `42`, `3.14`
- **Booleans**: `true`, `false`
- **Arrays**: `{"item1", "item2"}` or `{key="value"}`
- **Class constants**: Only `::class` magic constant is supported
- **Magic class constant**: `SomeClass::class`
- **Fully qualified names**: `\App\Models\User::class`
- **Imported classes**: `User::class` (when `use App\Models\User;` is present)

### Mixed Parameter Types

[](#mixed-parameter-types)

You can combine different parameter types within the same annotation:

```
/**
 * @ComplexAnnotation(
 *     type=User::class,
 *     name="user_service",
 *     priority=10,
 *     enabled=true,
 *     tags={"user", "service"}
 * )
 */
class UserService {
    // Class implementation
}
```

Configuration
-------------

[](#configuration)

The AnnotationReader requires a Configuration object that specifies:

- Whether to use annotation caching
- The path to store annotation cache files

Contributing
------------

[](#contributing)

Contributions are welcome! Please feel free to submit a Pull Request.

###  Health Score

37

—

LowBetter than 83% of packages

Maintenance75

Regular maintenance activity

Popularity11

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity46

Maturing project, gaining track record

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~6 days

Total

19

Last Release

269d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/57e4ab872b3e37536367f2d26b192df3d3bb6a6a1cebec9a104d14a6d2ffe157?d=identicon)[noescom](/maintainers/noescom)

###  Code Quality

TestsPest

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/quellabs-annotation-reader/health.svg)

```
[![Health](https://phpackages.com/badges/quellabs-annotation-reader/health.svg)](https://phpackages.com/packages/quellabs-annotation-reader)
```

###  Alternatives

[masterminds/html5

An HTML5 parser and serializer.

1.8k242.8M229](/packages/masterminds-html5)[sabberworm/php-css-parser

Parser for CSS Files written in PHP

1.8k191.2M65](/packages/sabberworm-php-css-parser)[jms/metadata

Class/method/property metadata management in PHP

1.8k152.8M88](/packages/jms-metadata)[jms/serializer-bundle

Allows you to easily serialize, and deserialize data of any complexity

1.8k89.3M627](/packages/jms-serializer-bundle)[hassankhan/config

Lightweight configuration file loader that supports PHP, INI, XML, JSON, and YAML files

97513.5M170](/packages/hassankhan-config)[meyfa/php-svg

Read, edit, write, and render SVG files with PHP

54613.9M42](/packages/meyfa-php-svg)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
