dentelis/php7-attribute-reader

Library for reading php8 attributes from legacy php7 code

Maintainers

Package info

github.com/dentelis/php7-attribute-reader

pkg:composer/dentelis/php7-attribute-reader

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

dev-main 2026-03-24 21:38 UTC

This package is auto-updated.

Last update: 2026-03-24 21:39:02 UTC


README

A library that brings PHP 8 attribute syntax to PHP 7.2+. The API mirrors PHP 8's native ReflectionAttribute as closely as possible, making future migration trivial.

PHP Version License

Installation

composer require dentelis/php7-attribute-reader

Quick Start

use AttributeReader\AttributeReader;

class UserController
{
    #[Route('/api/users', 'GET')]
    #[Auth('admin')]
    public function getUsers() {}
}

$method = new ReflectionMethod(UserController::class, 'getUsers');
$attributes = AttributeReader::getMethodAttributes($method);

foreach ($attributes as $attr) {
    echo $attr->getName();          // FQCN, e.g. "App\Attributes\Route"
    print_r($attr->getArguments()); // ['/api/users', 'GET']
    $instance = $attr->newInstance(); // Route object
}

Comparison with PHP 8

// PHP 8 native:
$method = new ReflectionMethod(UserController::class, 'getUsers');
$attrs = $method->getAttributes(Route::class);
$route = $attrs[0]->newInstance();

// This library (PHP 7.2+):
$method = new ReflectionMethod(UserController::class, 'getUsers');
$attrs = AttributeReader::getMethodAttributes($method, Route::class);
$route = $attrs[0]->newInstance();

Migration to PHP 8: replace AttributeReader::getMethodAttributes($method, ...) with $method->getAttributes(...).

API Reference

AttributeReader — Static Methods

All methods return Attribute[] and accept optional filtering parameters.

use AttributeReader\AttributeReader;
use AttributeReader\Attribute;

// Method attributes
AttributeReader::getMethodAttributes(ReflectionMethod $method, ?string $name = null, int $flags = 0): array;

// Class attributes
AttributeReader::getClassAttributes(ReflectionClass $class, ?string $name = null, int $flags = 0): array;

// Property attributes
AttributeReader::getPropertyAttributes(ReflectionProperty $property, ?string $name = null, int $flags = 0): array;

// Function attributes
AttributeReader::getFunctionAttributes(ReflectionFunction $function, ?string $name = null, int $flags = 0): array;

Parameters:

  • $name — filter by FQCN (exact match by default)
  • $flags0 (default) or Attribute::IS_INSTANCEOF (includes subclasses)

Attribute — Returned Object

$attr->getName(): string;        // Fully qualified class name
$attr->getArguments(): array;    // Parsed arguments (positional and/or named)
$attr->newInstance(): object;    // Instantiates the attribute class
$attr->isRepeated(): bool;       // True if the same attribute appears more than once

Constants:

  • Attribute::IS_INSTANCEOF = 2 — matches ReflectionAttribute::IS_INSTANCEOF

Features

Filtering

$method = new ReflectionMethod(Controller::class, 'index');

// All attributes
$all = AttributeReader::getMethodAttributes($method);

// By exact class
$routes = AttributeReader::getMethodAttributes($method, Route::class);

// By parent class (includes subclasses)
$all = AttributeReader::getMethodAttributes($method, BaseAttribute::class, Attribute::IS_INSTANCEOF);

Class Attributes

#[Controller('/api')]
#[Auth('admin')]
class UserController { }

$class = new ReflectionClass(UserController::class);
$attrs = AttributeReader::getClassAttributes($class);

Property Attributes

class User {
    #[Column('email', unique: true)]
    public $email;
}

$prop = new ReflectionProperty(User::class, 'email');
$attrs = AttributeReader::getPropertyAttributes($prop);

Named Arguments

#[Route(path: '/users', method: 'POST')]
#[Cache(ttl: 3600, enabled: true)]
#[Route('/api/users', method: 'POST')]  // mixed positional and named

Multiple Attributes

// Separate lines
#[Route('/admin')]
#[Auth('admin')]
public function dashboard() {}

// Comma-separated
#[Route('/admin'), Auth('admin')]
public function dashboard() {}

Repeated Attributes

#[Middleware('auth')]
#[Middleware('logging')]
public function index() {}

$attrs = AttributeReader::getMethodAttributes($method);
$attrs[0]->isRepeated(); // true

Expressions in Arguments

Arithmetic, bitwise, and string concatenation with correct operator precedence:

#[Cache(ttl: 60 * 60 * 24)]            // 86400
#[Cache(ttl: (2 + 3) * 10)]            // 50
#[Route(path: '/api' . '/users')]       // '/api/users'
#[Config(flags: 1 | 2 | 4)]            // 7
#[Cache(ttl: 2 ** 10)]                 // 1024

Supported operators: +, -, *, /, %, **, ., |, &, ^, ~, <<, >>

Constants in Arguments

Class constants, aliased imports, and global constants:

use App\Config\Limits;
use App\Config\Limits as L;

#[Cache(ttl: Limits::DEFAULT_TTL)]         // resolved via use statement
#[Cache(ttl: L::DEFAULT_TTL)]              // aliases work too
#[Cache(ttl: Limits::DEFAULT_TTL * 2)]     // expressions with constants
#[Cache(ttl: PHP_INT_SIZE)]                // global PHP constants
#[Config(name: Limits::APP_NAME . '-prod')]// concatenation with constants

Attribute Name Resolution

Attribute names are automatically resolved to FQCNs using the file's use statements and namespace — no explicit mapping required.

// In the source file:
use App\Attributes\Route;

#[Route('/users')]  // Resolved to "App\Attributes\Route"

Testing

composer test

Requirements

  • PHP 7.2 or higher

License

MIT

Credits

Developed by Dim Entelis