Мощный статический утилитарный класс для операций рефлексии PHP со встроенным кэшированием и продвинутой обработкой метаданных (атрибутов). Предоставляет удобные методы для работы с атрибутами PHP 8+ и объектами рефлексии.
- 🚀 Оптимизация производительности: Встроенное кэширование объектов рефлексии
- 🎯 Поддержка атрибутов: Комплексная обработка атрибутов PHP 8+
- 🔍 Глубокий поиск: Поиск атрибутов в членах класса (методы, свойства, константы)
- 🧩 Универсальная рефлексия: Умное создание рефлексии из различных типов данных
- 💾 Эффективность памяти: Автоматическое кэширование предотвращает дублирование объектов рефлексии
- 🔧 Типобезопасность: Полная поддержка дженерик типов для атрибутов
composer require bermudaphp/reflection- PHP 8.4 или выше
use Bermuda\Reflection\Reflection;
class UserController
{
#[Route('/api/users')]
#[Auth('admin')]
public function index(): Response
{
// реализация метода
}
}
$reflection = new ReflectionMethod(UserController::class, 'index');
// Получить все атрибуты
$attributes = Reflection::getMetadata($reflection);
// Получить атрибуты определённого типа
$routes = Reflection::getMetadata($reflection, Route::class);
// Получить первый атрибут определённого типа
$route = Reflection::getFirstMetadata($reflection, Route::class);
// Проверить существование атрибута
$hasAuth = Reflection::hasMetadata($reflection, Auth::class); // trueuse Bermuda\Reflection\Reflection;
// Автоматическое создание рефлексии для разных типов
$reflection = Reflection::reflect('MyClass'); // ReflectionClass
$reflection = Reflection::reflect($object); // ReflectionObject
$reflection = Reflection::reflect('function_name'); // ReflectionFunction
$reflection = Reflection::reflect([$obj, 'method']); // ReflectionMethod
$reflection = Reflection::reflect(fn() => true); // ReflectionFunctionПоиск атрибутов не только на самом классе, но и на всех его членах:
use Bermuda\Reflection\Reflection;
class UserService
{
#[Inject]
private UserRepository $repository;
#[Route('/users')]
#[Cache(ttl: 3600)]
public function getUsers(): array
{
return $this->repository->findAll();
}
#[Deprecated('Используйте getUsers() вместо этого')]
public const OLD_ENDPOINT = '/api/users';
}
$reflection = new ReflectionClass(UserService::class);
// Получить ВСЕ атрибуты из класса и его членов
$allAttributes = Reflection::getDeepMetadata($reflection);
/*
Возвращает:
[
'UserService::$repository' => [Inject],
'UserService::getUsers' => [Route, Cache],
'UserService::OLD_ENDPOINT' => [Deprecated]
]
*/
// Получить атрибуты определённого типа отовсюду в классе
$injectAttributes = Reflection::getDeepMetadata($reflection, Inject::class);
/*
Возвращает:
[
'UserService::$repository' => [Inject]
]
*/
// Получить первое вхождение атрибута в классе
$firstRoute = Reflection::getFirstDeepMetadata($reflection, Route::class);
// Проверить, есть ли атрибут где-либо в классе
$hasInject = Reflection::hasDeepMetadata($reflection, Inject::class); // trueРезультаты глубокого поиска используют описательные пути для идентификации места обнаружения атрибутов:
ClassName- Атрибут на самом классеClassName::methodName- Атрибут на методеClassName::$propertyName- Атрибут на свойствеClassName::CONSTANT_NAME- Атрибут на константе класса
Класс автоматически кэширует объекты рефлексии для улучшения производительности:
use Bermuda\Reflection\Reflection;
// Первый вызов создаёт и кэширует ReflectionClass
$reflection1 = Reflection::class('MyClass');
// Второй вызов возвращает кэшированный экземпляр (быстрее)
$reflection2 = Reflection::class('MyClass');
// $reflection1 === $reflection2 (тот же объект)
// Ручное добавление пользовательского рефлектора в кэш
Reflection::addReflector('my-key', $customReflector);public static function getMetadata(
ReflectionFunctionAbstract|ReflectionClass|ReflectionParameter|ReflectionConstant $reflector,
?string $name = null
): ?arrayПолучает все атрибуты из объекта рефлексии. Опционально фильтрует по имени класса атрибута.
$allAttributes = Reflection::getMetadata($reflection);
$routeAttributes = Reflection::getMetadata($reflection, Route::class);public static function getFirstMetadata(
ReflectionFunctionAbstract|ReflectionClass|ReflectionParameter|ReflectionConstant|ReflectionProperty $reflector,
string $name
): ?objectПолучает первый экземпляр атрибута указанного типа.
$route = Reflection::getFirstMetadata($methodReflection, Route::class);
if ($route) {
echo $route->path; // '/api/users'
}public static function hasMetadata(
ReflectionFunctionAbstract|ReflectionClass|ReflectionParameter|ReflectionConstant|ReflectionProperty $reflector,
string $name
): boolПроверяет, есть ли у объекта рефлексии атрибуты указанного типа.
if (Reflection::hasMetadata($reflection, Cache::class)) {
// Обработать логику кэширования
}public static function getDeepMetadata(
ReflectionClass $reflector,
?string $name = null
): arrayИщет атрибуты в классе и всех его членах (методы, свойства, константы).
// Получить все атрибуты отовсюду в классе
$allAttributes = Reflection::getDeepMetadata($classReflection);
// Получить только Route атрибуты отовсюду в классе
$routes = Reflection::getDeepMetadata($classReflection, Route::class);public static function getFirstDeepMetadata(
ReflectionClass $reflector,
string $name
): ?objectПолучает первый экземпляр атрибута, найденный где-либо в классе.
$firstRoute = Reflection::getFirstDeepMetadata($classReflection, Route::class);public static function hasDeepMetadata(
ReflectionClass $reflector,
string $name
): boolПроверяет, есть ли у класса или любого из его членов указанный атрибут.
if (Reflection::hasDeepMetadata($classReflection, Inject::class)) {
// Класс где-то использует внедрение зависимостей
}public static function reflect(mixed $var): null|ReflectionFunctionAbstract|ReflectionClass|ReflectionObjectУниверсальный метод рефлексии, который автоматически определяет подходящий тип рефлексии.
$reflection = Reflection::reflect('MyClass'); // ReflectionClass
$reflection = Reflection::reflect($instance); // ReflectionObject
$reflection = Reflection::reflect('strlen'); // ReflectionFunction
$reflection = Reflection::reflect([$obj, 'method']); // ReflectionMethodpublic static function callable(callable $callable): ReflectionFunctionAbstractСоздаёт рефлексию для вызываемых типов (функции, методы, замыкания).
$reflection = Reflection::callable('strlen'); // ReflectionFunction
$reflection = Reflection::callable([$obj, 'method']); // ReflectionMethod
$reflection = Reflection::callable(fn() => true); // ReflectionFunction
$reflection = Reflection::callable('Class::method'); // ReflectionMethodpublic static function object(object $object): ReflectionObjectСоздаёт кэшированный ReflectionObject для данного экземпляра объекта.
$reflection = Reflection::object($userInstance);
echo $reflection->getName(); // 'User'public static function class(string $class): ?ReflectionClassСоздаёт кэшированный ReflectionClass для данного имени класса. Возвращает null, если класс не существует.
$reflection = Reflection::class('User');
$reflection = Reflection::class('NonExistentClass'); // nulluse Bermuda\Reflection\Reflection;
class Container
{
public function autowire(string $className): object
{
$reflection = Reflection::class($className);
if (!$reflection) {
throw new Exception("Класс $className не найден");
}
$constructor = $reflection->getConstructor();
if (!$constructor) {
return new $className();
}
$dependencies = [];
foreach ($constructor->getParameters() as $parameter) {
$type = $parameter->getType();
if ($type && !$type->isBuiltin()) {
$dependencies[] = $this->autowire($type->getName());
}
}
return new $className(...$dependencies);
}
}use Bermuda\Reflection\Reflection;
class RouteDiscovery
{
public function discoverRoutes(array $controllerClasses): array
{
$routes = [];
foreach ($controllerClasses as $className) {
$reflection = Reflection::class($className);
// Найти все Route атрибуты в классе
$routeAttributes = Reflection::getDeepMetadata($reflection, Route::class);
foreach ($routeAttributes as $path => $attributes) {
foreach ($attributes as $route) {
$routes[] = [
'path' => $route->path,
'handler' => $path,
'methods' => $route->methods ?? ['GET']
];
}
}
}
return $routes;
}
}use Bermuda\Reflection\Reflection;
class Validator
{
public function validate(object $entity): array
{
$reflection = Reflection::object($entity);
$errors = [];
foreach ($reflection->getProperties() as $property) {
$value = $property->getValue($entity);
// Проверить атрибуты валидации
$required = Reflection::getFirstMetadata($property, Required::class);
if ($required && empty($value)) {
$errors[] = "{$property->getName()} обязательно для заполнения";
}
$length = Reflection::getFirstMetadata($property, Length::class);
if ($length && strlen($value) > $length->max) {
$errors[] = "{$property->getName()} слишком длинное";
}
}
return $errors;
}
}use Bermuda\Reflection\Reflection;
class EventManager
{
public function registerHandlers(object $listener): void
{
$reflection = Reflection::object($listener);
foreach ($reflection->getMethods() as $method) {
$eventHandler = Reflection::getFirstMetadata($method, EventHandler::class);
if ($eventHandler) {
$this->addEventListener(
$eventHandler->eventType,
[$listener, $method->getName()]
);
}
}
}
}- Используйте кэширование: Класс автоматически кэширует объекты рефлексии, поэтому предпочитайте использование статических методов вместо ручного создания новых рефлексий
- Используйте конкретные поиски: При поиске определённых типов атрибутов передавайте имя класса, чтобы избежать ненужной обработки
- Используйте глубокий поиск разумно: Используйте глубокий поиск только когда нужно искать в членах класса, поскольку он более затратный чем обычное получение метаданных
- Групповые операции: При работе с несколькими классами система кэширования обеспечивает значительные преимущества в производительности
Этот проект лицензирован под лицензией MIT - смотрите файл LICENSE для подробностей.