stubbles / reflect
反射辅助函数和注解。
Requires
- php: ^8.2
- stubbles/sequence: ^10.1
- stubbles/values: ^11.0
Requires (Dev)
- bovigo/assert: ^8.0
- mikey179/vfsstream: ^1.6.11
- phpunit/phpunit: ^10.5
This package is auto-updated.
Last update: 2024-08-31 15:50:05 UTC
README
反射辅助函数和注解。
构建状态
安装
stubbles/reflect 以 Composer 包的形式分发。要将它作为您包的依赖项安装,请使用以下命令
composer require "stubbles/reflect": "^10.0"
需求
stubbles/reflect 至少需要 PHP 8.2。
此外,它使用 stubbles/sequence 从某些函数返回序列,并使用 stubbles/values 从注解中解析值。
反射辅助函数
所有函数都在命名空间 stubbles\reflect
中。
reflect()
自 3.1.0 版本起可用
为了提供更多便利,提供了一个函数 stubbles\reflect\reflect()
。它允许反射类、对象和方法
$refClass = reflect('some\interesting\UserDefinedClass'); // creates instance of \ReflectionClass $refObject = reflect($someObjectInstance); // creates instance of \ReflectionObject $refMethod = reflect('some\interesting\UserDefinedClass', 'aMethod'); // creates instance of \ReflectionMethod $refMethod = reflect($someObjectInstance, 'aMethod'); // same as line before
自 4.0.0 版本起,它还允许反射函数
$refFunction = reflect('someFunction'); // creates instance of \ReflectionFunction
reflectConstructor(): \ReflectionMethod
为 reflect($someObject, '__construct')
的快捷方式
$refMethod = reflectConstructor('some\interesting\UserDefinedClass'); // same as reflect('some\interesting\UserDefinedClass', '__construct'); $refMethod = reflectConstructor($someObjectInstance); // same as reflect('some\interesting\UserDefinedClass', '__construct');
methodsOf($class, $filter = null): \stubbles\sequence\Sequence
返回给定类的所有方法的序列。
propertiesOf($class, $filter = null): \stubbles\sequence\Sequence
返回给定类的所有属性的序列。
parametersOf($classOrFunction, $methodName = null): \stubbles\sequence\Sequence
返回给定类的所有属性的序列。
parametersOfConstructor($class): \stubbles\sequence\Sequence
为 parametersOf($classOrFunction, '__construct')
的快捷方式。
parameter($name, $classOrFunction, $methodName = null): \ReflectionParameter
从引用的函数或方法中返回具有给定名称的参数。
constructorParameter($name, $class): \ReflectionParameter
为 parameter($name, $class, '__construct')
的快捷方式。
注解
有关注解背后的概念的详细信息,请参阅 注解,其中包含对该主题的通用介绍。有关如何在编程语言中使用此内容的更多详细信息,请参阅 Java 注解。
如何定义注解
注解可以定义在可以获取 docblock 注释的每个元素上:函数、方法、类和属性。此外,还可以在包含参数的函数或方法的 docblock 注释中定义注解。
namespace my; /** * Class to demonstrate how to define annotations * * @MyAnnotation */ class ExampleClass { /** * an example property * * @var string * @AnnotationWithValues(bar='dummy', baz=42, required=true) */ protected $bar; /** * another example property * * @var string * @AnnotationWithOneValue("anotherDummy") */ protected $baz; /** * an example method * * @param int $param a parameter * @CastedAnnotation[MyAnnotation] * @ParamAnnotation{param}(key='value') */ public function aMethod($param) { // some code here } }
在上面的例子中,你可以看到定义注解的五种不同方式。然而,你可以根据自己的喜好组合这些方式。你可能有一个没有、一个或多个值的 casted 注解。但让我们来回顾一下所有定义的注解。
- @MyAnnotation 这是一个没有值的注解。
- @AnnotationWithValues(bar='dummy', baz=42, required=true) 这个注解有两个值,参数 bar、baz 和 required。一个是字符串,另一个是整数,最后一个是一个布尔值。
- @AnnotationWithOneValue("anotherDummy") 这个注解只有一个字符串值。
- @CastedAnnotation[MyAnnotation] casted 注解可以用来区分标记和提示注解消费者类应执行的具体操作。第一个名称是标记,方括号中的名称表示要执行的操作。
- @ParamAnnotation{param}(key='value') 这个注解是为方法
aMethod()
的参数$param
定义的参数注解。花括号中的名称表示此注解所针对的参数的名称。请注意,当通过annotationsOf('Foo', 'aMethod')
获取它时,此注解不可用,这将导致ReflectionException
。
与其他实现不同,不需要为注解创建一个单独的类。
读取注解
要获取可注解元素的所有注解列表,请调用 stubbles\reflect\annotationsOf()
函数。它返回一个 stubbles\reflect\annotation\Annotations
实例,并支持以下调用
annotationsOf('my\ExampleClass', 'aMethod'); // returns annotations of this method annotationsOf($exampleInstance, 'aMethod'); // returns annotations of this method annotationsOf('my\ExampleClass'); // returns annotations of this class annotationsOf($exampleInstance); // returns annotations of this class annotationsOf('my\examplefunction'); // returns annotations of this function annotationsOf($reflectionParameter); // returns annotations of this parameter annotationsOf($reflectionProperty); // returns annotations of this class property
作为检索类构造函数注解的便捷函数,可以使用 stubbles\reflect\annotationsOfConstructorParameter()
annotationsOfConstructorParameter('my\ExampleClass'); annotationsOfConstructorParameter($exampleInstance);
作为检索函数或方法参数注解的便捷函数,可以使用 'stubbles\reflect\annotationsOfParameter()`
annotationsOfParameter('param', 'my\ExampleClass', 'aMethod'); annotationsOfParameter('param', $exampleInstance, 'aMethod'); annotationsOfParameter('param', 'someFunction');
从注解中读取值
如上所示,注解可以有值。如果我们从上面的类中取出 @AnnotationWithValues
,可以这样访问它们
$annotation = annotationsOf(/** reflectable annotation source */); echo $annotation->getBar(); // prints "dummy" echo $annotation->bar; // prints "dummy" echo $annotation->getValueByName('bar'); // prints "dummy" if ($annotation->isRequired()) { echo 'Required!'; }
这些是可能的方法
- 可以使用方法
is
后跟其名称来检索布尔值。 - 其他任何值类型都可以使用方法
get
后跟其名称来检索,作为注解类的属性,或使用getValueByName()
方法。 请注意,布尔值也可以使用get
方法的语法来检索,但大多数情况下看起来并不好:getRequired()
与isRequired()
在代码阅读者的观点上具有不同的含义。
如果注解只有一个无名的值,可以使用 $annotation->value
或 $annotation->getValue()
来检索。
使用 get
方法语法的好处是可以提供一个默认值,如果未设置具有此名称的值,则将返回该默认值
echo $annotation->getAwesomeness('Roland TB-303'); // prints "Roland TB-303"
is
方法语法的默认值是 false
。
如果值是可选的,可以检查其存在性:$annotation->hasValueByName('bar')
如果设置了具有名称 bar 的值,则返回 true
,否则返回 false
。
读取参数值时,它们将使用 stubbles/values 的 stubbles\values\Parse
进行解析。请参阅此包的文档了解如何解析值。
注解缓存
由于解析注解相当昂贵,Stubbles 会在读取后缓存注解。然而,默认情况下,缓存仅在请求级别上工作,并且不是持久的。为了在不同请求之间持久化注解缓存,应用程序需要提供注解缓存持久化。
这样做最简单的方法是调用 stubbles\reflect\annotation\persistAnnotationsInFile('/path/to/some/cachefile.cache')
,它将使用参数中指定的文件名来持久化注解缓存。
如果缓存文件不满足您的需求,您还可以提供不同的持久化。为此,您需要调用 stubbles\reflect\annotation\persistAnnotations()
并提供两个函数,一个函数可以读取数据并返回它,另一个函数可以接收数据并将其存储。对于文件缓存实现,它将如下所示
persistAnnotations( function() use($cacheFile) { if (file_exists($cacheFile)) { return unserialize(file_get_contents($cacheFile)); } return []; }, function(array $annotationData) use($cacheFile) { file_put_contents($cacheFile, serialize($annotationData)); } );
第一个函数必须返回存储的注解数据。如果不存在此类数据,它必须返回一个空数组。
第二个函数必须存储传入的注解数据。
请注意,如果您使用持久化注解缓存,您需要能够清除此缓存,因为代码中对注解的更改不会导致缓存数据的更新。这可能导致困惑,为什么更改后的注解在代码执行时不会被尊重。