kode / attributes
轻量级、健壮的PHP 8.1+属性读取器,为kodephp框架和主流PHP框架提供基础组件支持
Fund package maintenance!
1.2.3
2026-03-13 03:07 UTC
Requires
- php: ^8.1
- ext-json: *
- ext-mbstring: *
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.0
- phpunit/phpunit: ^10.0 || ^11.0 || ^12.0
README
一个轻量级、健壮的 PHP 8.1+ 属性(Attribute)读取器,为 kodephp 框架和主流 PHP 框架(Laravel、Symfony、ThinkPHP8、Webman 等)提供基础组件支持。
特性
- 零依赖 - 仅使用 PHP 原生功能,无第三方依赖
- 高性能 - 内置反射缓存机制,延迟实例化属性对象
- 类型安全 - 利用 PHP 8.1+ 的枚举和泛型特性
- IDE 友好 - 提供完整的 PHPStorm 元数据支持
- 协变支持 -
MetaList<@template-covariant T>支持类型安全的协变 - 框架无关 - 可在任何 PHP 8.1+ 项目中使用
- 安全封装 - 封装反射 API,避免直接暴露
ReflectionClass - 可扩展 - 可插拔缓存系统,支持自定义缓存驱动
安装
composer require kode/attributes
快速开始
基本用法
use Kode\Attributes\Attr; // 检查类是否具有特定属性 if (Attr::has(MyClass::class, MyAttribute::class)) { // 获取属性实例 $meta = Attr::get(MyClass::class, MyAttribute::class); $instance = $meta->getInstance(); } // 获取类的所有属性 $attributes = Attr::of(MyClass::class); foreach ($attributes as $meta) { echo $meta->name; // 属性类名 print_r($meta->args); // 属性参数 }
高级用法
use Kode\Attributes\Reader; use Kode\Attributes\ArrayCache; // 创建带自定义缓存的读取器 $cache = new ArrayCache(); $reader = new Reader($cache); // 获取类属性 $classAttrs = $reader->getClassAttrs(MyClass::class); // 获取方法属性 $methodAttrs = $reader->getMethodAttrs(MyClass::class, 'myMethod'); // 获取属性属性 $propertyAttrs = $reader->getPropertyAttrs(MyClass::class, 'myProperty'); // 获取缓存统计 $stats = $cache->getStats(); echo "缓存命中率: " . ($stats['hitRate'] * 100) . "%";
过滤与映射
use Kode\Attributes\Attr; // 过滤属性 $filtered = Attr::of(MyClass::class) ->filter(fn($meta) => is_subclass_of($meta->name, BaseAttribute::class)); // 映射属性为实例 $instances = Attr::of(MyClass::class) ->map(fn($meta) => $meta->getInstance()); // 获取所有指定类型的属性 $allRoutes = Attr::getAll(MyClass::class, Route::class); // 分组 $grouped = Attr::of(MyClass::class)->groupByName();
实际示例
路由定义
use Attribute; #[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] class Route { public function __construct( public readonly string $path, public readonly string $method = 'GET', public readonly string $name = '' ) {} } #[Route('/api/users', 'GET')] #[Route('/api/users', 'POST')] class UserController { #[Route('/api/users/{id}', 'GET')] public function getUser(int $id): void { // 方法实现 } } // 读取路由属性 $routes = Attr::of(UserController::class); // 过滤 POST 路由 $postRoutes = $routes->filter(fn($meta) => $meta->getInstance()->method === 'POST'); // 获取所有路径 $paths = $routes->map(fn($meta) => $meta->getInstance()->path);
权限控制
use Attribute; #[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] class Role { public function __construct( public readonly string $name, public readonly int $priority = 0 ) {} } #[Role('admin', 100)] #[Role('user', 50)] class AdminController { #[Role('super-admin', 200)] public function dangerousAction(): void { // 需要超级管理员权限 } } // 检查权限 $roles = Attr::of(AdminController::class) ->filter(fn($meta) => $meta->name === Role::class) ->map(fn($meta) => $meta->getInstance()->name); // 按优先级排序 $sortedRoles = Attr::of(AdminController::class) ->filter(fn($meta) => $meta->name === Role::class) ->sort(fn($a, $b) => $b->getInstance()->priority <=> $a->getInstance()->priority);
目录扫描
use Kode\Attributes\Attr; // 创建扫描器 $scanner = Attr::scan(__DIR__ . '/src'); // 排除特定目录 $scanner->exclude('vendor', 'tests', '.git'); // 查找所有带 Route 属性的类 foreach ($scanner->find(__DIR__ . '/src', Route::class) as $class => $metas) { echo "发现路由类: $class\n"; foreach ($metas as $meta) { $route = $meta->getInstance(); echo " - {$route->method} {$route->path}\n"; } } // 深度扫描(包含方法、属性) foreach ($scanner->scanDeep(__DIR__ . '/src') as $class => $info) { echo "类: $class\n"; echo " 类属性: " . count($info['class']) . "\n"; echo " 方法属性: " . count($info['methods']) . "\n"; echo " 属性属性: " . count($info['properties']) . "\n"; }
API 参考
主要类
| 类名 | 职责 |
|---|---|
Attr |
全局门面,提供静态访问入口 |
Reader |
属性读取器核心实现 |
Meta |
单个属性元数据封装 |
MetaList |
属性集合,支持链式操作 |
ArrayCache |
内存缓存实现 |
Scanner |
目录扫描器 |
Target |
属性目标类型枚举 |
Flags |
属性行为标志 |
关键接口
| 接口名 | 职责 |
|---|---|
ReaderInterface |
属性读取器契约 |
CacheInterface |
缓存驱动契约 |
Attr 门面
// 获取 Reader 实例 Attr::reader(): Reader // 设置自定义 Reader Attr::setReader(Reader $reader): void // 获取目标的所有属性 Attr::of(object|string $target): MetaList // 检查是否存在属性 Attr::has(object|string $target, string $attrClass): bool // 获取单个属性 Attr::get(object|string $target, string $attrClass): ?Meta // 获取所有指定类型属性 Attr::getAll(object|string $target, string $attrClass): MetaList // 创建扫描器 Attr::scan(string $dir): Scanner // 清除缓存 Attr::clear(): void
MetaList 集合方法
// 获取元素 $metaList->first(): ?Meta $metaList->last(): ?Meta $metaList->at(int $index): ?Meta $metaList->all(): array // 查询 $metaList->has(string $className): bool $metaList->get(string $className): ?Meta $metaList->getAll(string $className): MetaList $metaList->count(): int $metaList->isEmpty(): bool $metaList->isNotEmpty(): bool // 操作 $metaList->filter(callable $fn): MetaList $metaList->map(callable $fn): array $metaList->flatMap(callable $fn): array $metaList->each(callable $fn): void $metaList->some(callable $fn): bool $metaList->every(callable $fn): bool // 排序与分页 $metaList->sort(callable $comparator): MetaList $metaList->reverse(): MetaList $metaList->take(int $limit): MetaList $metaList->skip(int $offset): MetaList // 分组 $metaList->groupByName(): array $metaList->groupBy(callable $fn): array // 合并 $metaList->merge(MetaList $other): MetaList
Meta 元数据方法
// 基本信息 $meta->name: string // 属性类名 $meta->args: array // 属性参数 $meta->reflector: ?\Reflector // 所属反射对象 // 实例化 $meta->getInstance(): object $meta->newInstance(): object // 目标信息 $meta->getTarget(): Target $meta->supportsTarget(Target $target): bool $meta->isRepeatable(): bool // 参数访问 $meta->getArgument(string $name, mixed $default = null): mixed $meta->getNamedArguments(): array $meta->getPositionalArguments(): array // 其他 $meta->getDeclaringClass(): ?string $meta->toArray(): array
Target 枚举
use Kode\Attributes\Target; // 枚举值 Target::Clazz // 类 Target::Function // 函数 Target::Method // 方法 Target::Property // 属性 Target::ClassConstant // 类常量 Target::Parameter // 参数 Target::All // 全部 // 静态方法 Target::fromRef(\Reflector $ref): Target Target::fromAttributeFlags(int $flags): Target // 实例方法 $target->supports(Target $other): bool $target->combine(Target ...$others): Target $target->getTargets(): array $target->toAttributeFlags(): int $target->getLabel(): string // 中文标签 $target->toString(): string
Flags 标志类
use Kode\Attributes\Flags; // 创建实例 new Flags( inherit: bool, // 是否继承 compileTime: bool, // 是否编译期处理 priority: int, // 优先级 cacheable: bool // 是否可缓存 ) // 静态工厂方法 Flags::inherit(int $priority = 0): Flags Flags::compileTime(int $priority = 0): Flags Flags::highPriority(int $priority = 100): Flags Flags::nonCacheable(): Flags // 实例方法 $flags->isDefault(): bool $flags->merge(Flags $other): Flags $flags->toArray(): array $flags->__toString(): string
自定义缓存驱动
use Kode\Attributes\CacheInterface; class RedisCache implements CacheInterface { private \Redis $redis; public function __construct(\Redis $redis) { $this->redis = $redis; } public function get(string $key, callable $loader): mixed { $value = $this->redis->get($key); if ($value === false) { $value = $loader(); $this->redis->set($key, serialize($value)); } return is_string($value) ? unserialize($value) : $value; } public function has(string $key): bool { return $this->redis->exists($key) > 0; } public function set(string $key, mixed $value): void { $this->redis->set($key, serialize($value)); } public function delete(string $key): void { $this->redis->del($key); } public function clear(): void { $this->redis->flushDB(); } } // 使用自定义缓存 $reader = new Reader(new RedisCache($redis)); Attr::setReader($reader);
系统要求
- PHP >= 8.1
- ext-json
- ext-mbstring
兼容性
| PHP 版本 | 支持状态 |
|---|---|
| PHP 8.1 | ✅ 完全支持 |
| PHP 8.2 | ✅ 完全支持 |
| PHP 8.3 | ✅ 完全支持 |
| PHP 8.4 | ✅ 完全支持 |
| PHP 8.5 | ✅ 完全支持(优先使用新特性) |
框架兼容性
| 框架 | 支持状态 |
|---|---|
| Laravel | ✅ 完全兼容 |
| Symfony | ✅ 完全兼容 |
| ThinkPHP 8 | ✅ 完全兼容 |
| Webman | ✅ 完全兼容 |
| Hyperf | ✅ 完全兼容 |
| 原生 PHP | ✅ 完全兼容 |
测试
# 运行测试 composer test # 生成覆盖率报告 composer test:coverage # 代码风格检查 composer check # 代码风格修复 composer fix
贡献
欢迎提交 Issue 和 Pull Request 来改进这个项目。
贡献指南
- Fork 本仓库
- 创建特性分支 (
git checkout -b feature/AmazingFeature) - 提交更改 (
git commit -m 'Add some AmazingFeature') - 推送到分支 (
git push origin feature/AmazingFeature) - 创建 Pull Request
许可证
本项目基于 Apache License 2.0 开源协议发布。
作者
KodePHP - 382601296@qq.com
致谢
感谢所有为这个项目做出贡献的开发者!