注解在Java中使用的非常广泛
在php8中正式的加入了注解的功能
注解功能使得代码中的声明部分都可以添加结构化、机器可读的元数据, 注解的目标可以是类、方法、函数、参数、属性、类常量。
通过 反射API 可在运行时获取注解所定义的元数据。 因此注解可以成为直接嵌入代码的配置式语言
说人话就是,注解实现的原理是反射,通过动态代理模式可以直接嵌入代码的配置,注解可以作用在类,方法,函数,参数,属性和常量上面。
使用注解可以在实现功能、使用功能相互解耦
在php中,注解的语法是总是以 #[
开头,以 ]
结尾来包围。内部则是一个或以逗号包含的多个注解,注解的名称使用命名空间,可以是非限定、限定、完全限定的名称。注解的参数是可以选的,以常见的括号()
包围。 注解的参数可以是字面值或者常量表达式。 它同时接受位置参数和命名参数两种语法。
例如:#[Attribute] #[注解名称]
通过反射 API 请求注解实例时,注解的名称会被解析到一个类,注解的参数则传入该类的构造器中。 因此每个注解都需要引入一个类
<?php
// a.php
namespace MyExample;
use Attribute;
#[Attribute] //作用在类上面的注解
class MyAttribute
{
const VALUE = 'value';
private $value;
public function __construct($value = null)
{
$this->value = $value;
}
}
// b.php
namespace Another;
use MyExample\MyAttribute;
#[MyAttribute]
#[\MyExample\MyAttribute]
#[MyAttribute(1234)]
#[MyAttribute(value: 1234)]
#[MyAttribute(MyAttribute::VALUE)]
#[MyAttribute(array("key" => "value"))]
#[MyAttribute(100 + 200)]
class Thing
{
}
#[MyAttribute(1234), MyAttribute(5678)]
class AnotherThing
{
}
反射 API 提供了 getAttributes() 方法, 类、方法、函数、参数、属性、类常量的反射对象可通过它获取相应的注解。 该方法返回了 ReflectionAttribute 实例的数组, 可用于查询注解名称、参数、也可以实例化一个注解。
实例和反射注解的分离使得程序员增加了在丢失反射类、类型错误、丢失参数等情况下的处理能力,也能处理错误。 只有调用 newInstance() 后,注解类的对象才会以验证过匹配的参数来实例化。
通过反射 API 读取注解
<?php
#[Attribute]
class MyAttribute
{
public $value;
public function __construct($value)
{
$this->value = $value;
}
}
#[MyAttribute(value: 1234)]
class Thing
{
}
function dumpAttributeData($reflection) {
$attributes = $reflection->getAttributes();
foreach ($attributes as $attribute) {
var_dump($attribute->getName());
var_dump($attribute->getArguments());
var_dump($attribute->newInstance());
}
}
dumpAttributeData(new ReflectionClass(Thing::class));
/*
string(11) "MyAttribute"
array(1) {
["value"]=>
int(1234)
}
object(MyAttribute)#3 (1) {
["value"]=>
int(1234)
}
*/
声明注解类
虽然没有严格要求,推荐为每个注解创建一个实际的类。 在这个最简单的例子中,通过 use 语法从全局命名空间引入 #[Attribute]
注解所需要全空的类。
<?php
namespace Example;
use Attribute;
#[Attribute]
class MyAttribute
{
}
要限制指定注解的声明类型,可为 #[Attribute]
注解第一个参数传入字节位掩码设置。
<?php
namespace Example;
use Attribute;
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_FUNCTION)]
class MyAttribute
{
}
在另一个类型中声明 MyAttribute 会在调用 ReflectionAttribute::newInstance() 时抛出异常。
注解在每个声明中默认情况下只能使用一次。 如果需要重复,可以在 #[Attribute]
声明中设置字节位掩码。
<?php
namespace Example;
use Attribute;
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_FUNCTION | Attribute::IS_REPEATABLE)]
class MyAttribute
{
}
target:指定了注解的作用域