php8新特性,对attributes注解功能的一些片面理解
发布于 作者:苏南大叔 来源:程序如此灵动~attribute
,这个难道不是翻译成“属性”么?为啥各位大大都翻译成注解?因为其它的高级编程语言(Java
)里面,这个功能叫做注解。那么,注解和注释有啥区别和联系?这里有十万个为什么等着大家。
苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码感想感悟。测试环境:win10
,nginx@1.15.11
,php@8.2.10-nts
。
片面的整体印象
先说一下苏南大叔的总体感受吧,对比其它java
或者python
高级编程语言的类似功能,感觉这个php8
的attribute
并不好用。很片面的看法,欢迎大家提出不同意见。
也许官方也不认为这个attribute
功能是注解,否则为什么不使用annotation
这个单词?(前期使用的官方名称甚至是phpAttribute
。)但是,如果把它翻译成“属性”的话,那么如何区别对待本来就已经有的Properties
属性?所以,苏南大叔更倾向于使用原版的单词attribute
,不翻译为属性,也不翻译为注解。
对标=>标准化注释
根据各位国内外大神的描述,苏南大叔理解着,这个attribute
对标的就是php
的注释,或者说是phpdocumentor
的标准注释。(世面上无此说法,苏南大叔自己的理解。)
因为根据phpdoc
的标准注释方法,每个类或者方法,前面都有这样类似的注释。而且一些工具可以识别这些注释,并转化为具体的代码提示功能。如果抛弃别的工具去识别这些注释的话,对于普通的程序员来说,这些就是格式化的非常好的注释文本而已。
/**
* @param string $name
* @param string $category
**/
function pet($name, $category) {}
phpDocumentor
的使用方式:
Attribute 历史变革
即使都是在php8
时代,这个attribute
特性就有两次相互不兼容的更新了。而且鉴于attribute
特性的极其匪夷所思的难用性,苏南大叔推断以后还会有大的功能变更,甚至取消该特性。
最早php@8.1
的的phpAttribute
版本,是类似这样的:
use \Support\attribute\ListensTo;
class ProductSubscriber
{
<<ListensTo(ProductCreated::class)>>
public function onProductCreated(ProductCreated $event) { /* … */ }
<<ListensTo(ProductDeleted::class)>>
public function onProductDeleted(ProductDeleted $event) { /* … */ }
}
php@8.2
的Attribute
版本,是类似这样的:
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_FUNCTION)]
class pet {
public function __construct(string $name, int $category_id){}
}
#[pet('api/pet/1', 5)]
function getPet() {}
Attribute 到底是个啥
在php8
时代,attribute
特性试图另外一种方式去解释这些注释,而且放置的位置就是在函数或类定义的前方位置。并且使用特殊符号进行标记,这确实和java
的注解/python
的装饰器功能非常类似。
但是,java
的注解/python
的装饰器,会联动代码,进而影响运行结果的不同。但是,这个php
的attribute
,虽然也能联动代码。但是,并不会影响运行结果。最多只能说是:把php
的注释文本给可编程化了。但是,目前运行的结果依然是注释文本,只能起到特定情形下的代码提示作用。
除非在特定的框架下,可能会把这个attribute
功能给用起来。目前这种情况,不在考虑范围内。
普通 attribute 定义使用
写法是#[]
,例如:
#[Name]
#[Name1, Name2,...]
#[Name(Arguments)]
#[Name(Arguments1, Arguments2, ArgumentsN)]
#[Name1(Arguments), Name2(Arguments)]
普通的情况下,是这样定义的:
#[url('api/pet/1', methods:['GET']), param('id')]
function getPet( $id ) {}
定义的这些attribute
信息,都是可以利用反射reflection
来获取到的,这也是目前已知的唯一使用场景。可以使用reflection
来拿到或拆分这些字符串信息。(这里的url
换成其它的字符串也是可以的,随便写。)
使用的方式是:
$ref = new ReflectionFunction('getPet');
$attrs = $ref->getAttributes();
print_r($attrs);
echo $attrs[0]->getName();
print_r($attrs[0]->getArguments());
输出:
Array
(
[0] => ReflectionAttribute Object
(
)
[1] => ReflectionAttribute Object
(
)
)
url
Array
(
[0] => api/pet/1
[methods] => Array
(
[0] => GET
)
)
可编程化的 attribute
当attribute
主动实例化的时候,就会调用其可编程的功能。比如:
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_FUNCTION)]
class pet {
public function __construct(string $name, int $category_id) {
echo $name, $category_id; // 这个是输出的文字
}
}
#[pet('哈吉米', 1)]
function getPet() {}
//#####################################
$ref = new ReflectionFunction('getPet');
$attr = $ref->getAttributes()[0];
$attr->newInstance(); // 这个时候实例化的是pet类..
代码解释
上面的代码中,有两个部分:
- 第一种,给其它类或函数方法,专门提供
attribute
功能的类pet
。 - 第二种,被
attribute
的函数getPet
,它可以写普通的函数或字符标记。也可以调用第一种类,以形成特定功能。
attribute的适用范围
它虽然名义上是为其它类或方法函数,提供attribute
功能的。但是,它也可以主动选择其服务对象的范围。这些范围可以参考:
代码 | 名称 |
---|---|
Attribute::TARGET_CLASS | class |
Attribute::TARGET_FUNCTION | function |
Attribute::TARGET_METHOD | method |
Attribute::TARGET_PROPERTY | PROPERTY |
Attribute::TARGET_CLASS_CONSTANT | CLASS_CONSTANT |
Attribute::TARGET_PARAMETER | PARAMETER |
Attribute::TARGET_ALL | ALL |
比如下面的代码,就会报错。因为pet
类规定了,其服务的主体只能是TARGET_CLASS
。所以,把它注释到TARGET_FUNCTION
上,就属于违背其主体意愿了。所以,报错了。
#[Attribute(Attribute::TARGET_CLASS)]
class pet {
public function __construct(string $name, int $category_id) {}
}
#[pet('哈吉米', 1)]
function getPet() {}
// ####################################
$ref = new ReflectionFunction('getPet');
$attr = $ref->getAttributes()[0];
$attr->newInstance(); // 这个时候才报错...
输出:
Fatal error: Uncaught Error: Attribute "pet" cannot target function (allowed targets: class)
鸡肋 attribute
必须强调一点,这个可编程化的attribute
,对于正常的代码逻辑是一丁点影响都没有的。因为目前它的已知的唯一使用场景,依然是反射reflection
,而正常的业务逻辑里面是不会用到反射功能的!
虽然,在这个过程中,是可以输出一些内容,执行一些操作的。但是这功能是不是很鸡肋...很像是黑客留的后门场所呢...因为正常的代码,谁会用反射?用了反射,还纠结出某个注解功能,然后再把这个注解给实例化?
苏南大叔的意思是:并不是自动执行的attribute
功能,而且是使用了比较罕见的反射的场景方式去刻意执行?
相关文档
- https://newsn.net/say/php8-function.html
- https://newsn.net/say/php8-class.html
- https://newsn.net/say/php8-null-check.html
- https://newsn.net/say/php8-match.html
结束语
苏南大叔不是很喜欢这个php8
的新特性attribute
,因为毕竟相比较java
的注解/python
的装饰器来说,它缺少了主动执行解释,并影响代码走向的功能或使用场景。
如果仅仅是一个变着花样的注释功能,那么,新特性attribute
不要也罢。更多苏南大叔的php
经验文章,请点击:
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。