ryunosuke / utility-attribute
实用属性
v1.1.2
2024-08-29 13:33 UTC
Requires
- php: >=8.0
Requires (Dev)
README
描述
此包提供通用/有用的属性。
安装
{ "require": { "ryunosuke/utility-attribute": "*" } }
用法
见下文。
<?php require_once __DIR__ . '/vendor/autoload.php'; use ryunosuke\utility\attribute\Attribute\AbstractAttribute; use ryunosuke\utility\attribute\Attribute\DebugInfo; use ryunosuke\utility\attribute\Attribute\Friend; use ryunosuke\utility\attribute\Attribute\Json; use ryunosuke\utility\attribute\ClassTrait\DebugInfoTrait; use ryunosuke\utility\attribute\ClassTrait\FriendTrait; use ryunosuke\utility\attribute\ClassTrait\JsonTrait; use ryunosuke\utility\attribute\ReflectionAttribute; #[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)] class SampleAttribute1 extends AbstractAttribute { public function __construct(int $a, $b = 2, $c = 3) { } } #[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)] class SampleAttribute2 extends AbstractAttribute { } /** * below comment is autogenerated by annotate. * * @auto-document-Friend:begin * @property int $privateField * @auto-document-Friend:end */ #[SampleAttribute1(1, c: 9)] class SampleClass implements JsonSerializable { use DebugInfoTrait; use FriendTrait; use JsonTrait; #[Friend] #[DebugInfo(false), Json(true)] private int $privateField = 123; #[Json(false)] public int $publicField = 456; #[SampleAttribute1(1)] public function method() { } } #[SampleAttribute2] class SampleSubClass extends SampleClass { public function method() { return parent::method(); } } $sample = new SampleClass(); $subsample = new SampleSubClass(); # Get attribute by following inheritance tree var_dump(SampleAttribute1::of($subsample->method(...), 0)); /*= NULL */ var_dump(SampleAttribute1::of($subsample->method(...), ReflectionAttribute::FOLLOW_INHERITANCE)); /*= object(ryunosuke\utility\attribute\ReflectionAttribute)#12 (1) { ["SampleAttribute1"]=> array(3) { ["a"]=> int(1) ["b"]=> int(2) ["c"]=> int(3) } } */ # Get attribute by seeing class also var_dump(SampleAttribute2::of($subsample->method(...), 0)); /*= NULL */ var_dump(SampleAttribute2::of($subsample->method(...), ReflectionAttribute::SEE_ALSO_CLASS)); /*= object(ryunosuke\utility\attribute\ReflectionAttribute)#13 (1) { ["SampleAttribute2"]=> array(0) { } } */ # Get attribute by following inheritance tree & seeing class also & merge repeatable var_dump(SampleAttribute1::arrayOf($sample->method(...), ReflectionAttribute::ALL)); /*= array(2) { [0]=> object(ryunosuke\utility\attribute\ReflectionAttribute)#10 (1) { ["SampleAttribute1"]=> array(3) { ["a"]=> int(1) ["b"]=> int(2) ["c"]=> int(3) } } [1]=> object(ryunosuke\utility\attribute\ReflectionAttribute)#11 (1) { ["SampleAttribute1"]=> array(3) { ["a"]=> int(1) ["b"]=> int(2) ["c"]=> int(9) } } } */ # Get attribute without Reflection var_dump(SampleAttribute1::arrayOf($sample)); /*= array(1) { [0]=> object(ryunosuke\utility\attribute\ReflectionAttribute)#12 (1) { ["SampleAttribute1"]=> array(3) { ["a"]=> int(1) ["b"]=> int(2) ["c"]=> int(9) } } } */ # Single version above $attr = SampleAttribute1::of($sample); # ReflectionAttribute implements getReflection var_dump($attr->getReflection()); /*= object(ReflectionObject)#12 (1) { ["name"]=> string(11) "SampleClass" } */ # ReflectionAttribute implements getNamedArguments var_dump($attr->getNamedArguments()); /*= array(3) { ["a"]=> int(1) ["b"]=> int(2) ["c"]=> int(9) } */ # Compare getArguments and above var_dump($attr->getArguments()); /*= array(2) { [0]=> int(1) ["c"]=> int(9) } */ # ReflectionAttribute implements getNamedArgument var_dump($attr->getNamedArgument('c')); /*= int(9) */ # Same as $params = $attr->getArguments(); var_dump(array_key_exists(2, $params) ? $params[2] : (array_key_exists('c', $params) ? $params['c'] : null)); /*= int(9) */ # But native doesn't do this var_dump($attr->getNamedArgument('b')); /*= int(2) */ # Access private field by Friend var_dump($sample->privateField); /*= int(123) */ var_dump($subsample->privateField); /*= int(123) */ # $privateField is invisible at var_dump by DebugInfo var_dump($sample); /*= object(SampleClass)#5 (1) { ["publicField"]=> int(456) } */ # $privateField is visible/$publicField is invisible at json_encode by Json var_dump(json_encode($sample, JSON_PRETTY_PRINT)); /*= string(27) "{ "privateField": 123 }" */ # Rewrite SampleClass DocComment $sample->annotate(); ?>
注意
个人感觉,使用PHP标准属性获取存在以下不便之处。
- 不想通过反射来获取
- 希望直接使用手头的class-string或实例来获取
- 通常不会不指定name来获取
- 那么,以Attribute类为主体来获取会方便一些
- 重复属性比单次属性用途更广
- 那么,不如用数组返回,而是用?Attribute返回,这样更方便使用
- getArguments实际上返回arguments,使用起来不太方便
- 因此不得不添加一些奇怪的分支,希望统一使用命名参数来获取
- 希望将类的属性用作成员属性的默认值
- 例如,PHPUnit的@group之类的。这种场景相当多
- 仅仅委托方法就会导致属性消失
- 如果完全覆盖,通常需要原始方法的属性
发布
版本控制是浪漫版本控制(非语义版本控制)。
- major:大的BC(向后兼容性)破坏。例如,更改架构、包、类等
- minor:小的BC破坏。例如,更改参数、返回类型等
- patch:没有BC破坏。例如,修复错误、添加可选参数、代码格式等
1.1.2
- [fixbug] 可变长参数时无法获取值的问题
1.1.1
- [feature] 修复php8.2的错误
1.1.0
- [change] php>=8.0
1.0.2
- [feature] 添加MERGE_REPEATABLE
1.0.1
- 修复示例
1.0.0
- 发布
许可证
MIT