我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

attribute,这个难道不是翻译成“属性”么?为啥各位大大都翻译成注解?因为其它的高级编程语言(Java)里面,这个功能叫做注解。那么,注解和注释有啥区别和联系?这里有十万个为什么等着大家。

苏南大叔:php8新特性,对attributes注解功能的一些片面理解 - php8注解功能
php8新特性,对attributes注解功能的一些片面理解(图4-1)

苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码感想感悟。测试环境:win10nginx@1.15.11php@8.2.10-nts

片面的整体印象

先说一下苏南大叔的总体感受吧,对比其它java或者python高级编程语言的类似功能,感觉这个php8attribute并不好用。很片面的看法,欢迎大家提出不同意见。

也许官方也不认为这个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.2Attribute版本,是类似这样的:

#[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的装饰器,会联动代码,进而影响运行结果的不同。但是,这个phpattribute,虽然也能联动代码。但是,并不会影响运行结果。最多只能说是:把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
        )

)

苏南大叔:php8新特性,对attributes注解功能的一些片面理解 - 最简单的注解使用
php8新特性,对attributes注解功能的一些片面理解(图4-2)

可编程化的 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类..

苏南大叔:php8新特性,对attributes注解功能的一些片面理解 - 复杂点的注解写法
php8新特性,对attributes注解功能的一些片面理解(图4-3)

代码解释

上面的代码中,有两个部分:

  • 第一种,给其它类或函数方法,专门提供attribute功能的类pet
  • 第二种,被attribute的函数getPet,它可以写普通的函数或字符标记。也可以调用第一种类,以形成特定功能。

attribute的适用范围

它虽然名义上是为其它类或方法函数,提供attribute功能的。但是,它也可以主动选择其服务对象的范围。这些范围可以参考:

代码名称
Attribute::TARGET_CLASSclass
Attribute::TARGET_FUNCTIONfunction
Attribute::TARGET_METHODmethod
Attribute::TARGET_PROPERTYPROPERTY
Attribute::TARGET_CLASS_CONSTANTCLASS_CONSTANT
Attribute::TARGET_PARAMETERPARAMETER
Attribute::TARGET_ALLALL

比如下面的代码,就会报错。因为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)

苏南大叔:php8新特性,对attributes注解功能的一些片面理解 - 注解的适用范围
php8新特性,对attributes注解功能的一些片面理解(图4-4)

鸡肋 attribute

必须强调一点,这个可编程化的attribute,对于正常的代码逻辑是一丁点影响都没有的。因为目前它的已知的唯一使用场景,依然是反射reflection,而正常的业务逻辑里面是不会用到反射功能的!

虽然,在这个过程中,是可以输出一些内容,执行一些操作的。但是这功能是不是很鸡肋...很像是黑客留的后门场所呢...因为正常的代码,谁会用反射?用了反射,还纠结出某个注解功能,然后再把这个注解给实例化?

苏南大叔的意思是:并不是自动执行的attribute功能,而且是使用了比较罕见的反射的场景方式去刻意执行?

相关文档

结束语

苏南大叔不是很喜欢这个php8的新特性attribute,因为毕竟相比较java的注解/python的装饰器来说,它缺少了主动执行解释,并影响代码走向的功能或使用场景。

如果仅仅是一个变着花样的注释功能,那么,新特性attribute不要也罢。更多苏南大叔的php经验文章,请点击:

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   php