Press "Enter" to skip to content

PHP 8新特性之Attributes(注解)

PHP8的Alpha版本,过几天就要发布了,其中包含了不少的新特性,当然我自己认为最重要的还是JIT,这个我从2013年开始参与,中间挫折无数,失败无数后,终于要发布的东东。

不过,今天呢,我不打算谈JIT,等PHP8发布了以后,我再单独写个类似《深入理解PHP8之JIT》系列来说吧。

嘿嘿,今天呢,我想谈谈Attributes,为啥呢, 是昨天我看到很多群在转发一个文章,叫做《理解PHP8中的Attributes》,说实在的,这篇文章应该是直接从英文翻译过来的,写的晦涩难懂,很多同学看完以后表示,看的一头雾水,不知道在说啥。

于是我想,就用一篇文章来简单说说这是个啥。

后记(2020/09/07), 最新的RFC投票通过,把注解的符号从<<>>, 改成了#[], 所以此文做了更新,使用最新的注解符号

说注解之前,先说说以前的注释,我们经常会在PHP的项目中,看到的一个东西,类似如下的@param 和 @see :

/**
 * @param Foo $argument
 * @see https:/xxxxxxxx/xxxx/xxx.html
 */    
 function dummy($Foo) {}

这个叫做注释,对于以前的PHP来说,注释中的@param和@see毫无意义,整个这一段会保存为一个函数/方法的一个叫做doc_comment的字符串。

如果我们要分析这段注释的含义,我们需要通过设计一些特定的语法,就比如栗子中的@+name, 类似@param一样, 然后自己分析这段字符串,来提取对应的信息。

比如我们要获取See这个注释的信息,我们需要做类似:

$ref = new ReflectionFunction("dummy");
$doc = $ref->getDocComment();
$see = substr($doc, strpos($doc, "@see") + strlen("@see "));

这样的字符串处理,相对比较麻烦,也比较容易出错。

而Attributes呢,其实就是把“注释”升级为支持格式化内容的“注解”

比如上面的例子:

#[Params("Foo", "argument")]
#[See("https://xxxxxxxx/xxxx/xxx.html")]
function dummy($argument) {}

当有多个注解的时候,你也可以写成:

#[
 Params("Foo", "argument"),
 See("https://xxxxxxxx/xxxx/xxx.html")
]
function dummy($argument) {}

大家不要纠结这么写的意义是啥,从功能上来说,现在你就可以通过Reflection来获取这段格式化的注解了,比如, 我们现在要获取See这个注解:

$ref = new ReflectionFunction("dummy");

var_dump($ref->getAttributes("See")[0]->getName());
var_dump($ref->getAttributes("See")[0]->getArguments());

会输出:

string(3) "See"
array(1) {
  [0]=>
  string(30) "https://xxxxxxxx/xxxx/xxx.html"
}

当然,还有稍微高级一点的用法,就是你可以定义一个所谓的“注解类”:

<?php
#[Attribute(Attribute::TARGET_FUNCTION)]
class MyAttribute {
	public function __construct($name, $value) {
		var_dump($name);
		var_dump($value);
	}
}

然后, 你就可以写类似, 注意其中的newInstance调用:

#[MyAttribute("See", "https://xxxxxxxx/xxxx/xxx.html")]
function dummy($argument) {
}
$ref = new ReflectionFunction("dummy");

$ref->getAttributes("MyAttribute")[0]->newInstance();

如果你跑这段代码,你会看到MyAttribute的__construct方法被调用了, 调用传递的参数就是”See”和”https://xxx”

明白了么, 就是你可以把一个注解“实例化”, 然后,你就可以基于这个能力,来做自己的“注释即配置”的设计。

总结下Attributes的写法就是如下的形式:

#[Name]
#[Name(Arguments)]
#[Name(Argunment1, Arguments2, ArgumentN)]

#[Name1(Argument), Name2(Argument), Name3(Argument)]

然后你就可以通过PHP的Reflection系列的方法,根据getAttributes("Name")获取对应的注解, 进一步你可以通过调用返回的注解的getName方法获取名字,getArguments方法获取括号中的Arguments。

再进一步,如果Name是一个你自己定义的注解类,通过#[Attribute(Attribute::TARGET_FUNCTION)], 或者:

TARGET_CLASS    //类的注解类
TARGET_FUNCTION //函数注解类
TARGET_METHOD   //方法注解类
TARGET_PROPERTY //属性注解类
TARGET_CLASS_CONSTANT //类常量注解类
TARGET_PARAMETER //参数注解类
TARGET_ALL 

来表明注解类应用的目标类型,然后你就可以调用newInstance方法,实现类似"new Name(Arguments)"的调用。

也许很多人会问,这有什么卵用?

坦白说,我一直对新特性无感,但这个Attributes,多少还是应该有那么一点点吧 🙂

76 Comments

  1. redactle
    redactle May 9, 2023

    Your article was interesting. Do you want to try something new? If that’s the case, you can try it right now online.

  2. Alex
    Alex April 18, 2023

    Watch Full HD kshows and Drama cool Dramacool for everyone!

  3. ThinkYoung
    ThinkYoung March 1, 2022

    大神,请问如何自动注入 注解呢?
    感觉这个例子不太全啊?

    • ThinkYoung
      ThinkYoung March 2, 2022

      PHP8后续,能不能提供出内置注解呢?

  4. Tony
    Tony September 24, 2021

    还是java的@注解更好看,这语法当真有点丑

  5. krunker
    krunker August 19, 2021

    一篇很棒的文章,里面有很多信息,这些文章可以帮助对网站感兴趣的用户

  6. 路人甲
    路人甲 May 28, 2021

    应该完全重新构建整个PHP语言,历史遗留问题太多了,要抛弃历史包袱,充分借鉴其他语言的好的特性,保留PHP中的一些精华,完全重构。不然这样东打一个补丁,西打一个补丁的,越来越像四不像了。各种耍小聪明的语法糖 和特性,让整个PHP简直像风雨中飘摇着随时可能倒塌的灯塔,仿佛已经能听到它吱呀吱呀的不堪重负的呻吟。

    • eric
      eric August 9, 2021

      自作聪明罢了

  7. guofu
    guofu May 27, 2021

    看了好几遍,翻了一下官方文档,还是不清楚 php8.0选择升级维护 注解的意义是什么?能举个栗子吗

  8. Lukexp
    Lukexp May 24, 2021

    强行穿透了注释和代码的界限,感觉还是弊大于利吧

  9. Jimmy
    Jimmy May 19, 2021

    确实,PHP8的这些新特性,新的语法糖,不但没有让人眼前一亮,反而看来只会把原本简单事情搞的更糟,有点失望。

  10. canliture
    canliture April 19, 2021

    PHP越发展越靠近Java。
    用啥#,用@不好吗?就是因为防止自己被说成模仿Java?

  11. 爆肝
    爆肝 March 4, 2021

    刚看了php8 的特性 百度了下php注解,搜到这里。
    好奇为什么不用@Value() 这种做注解啊,多么的实用经济和熟悉呢。
    差评。好难看的###

  12. alang
    alang February 17, 2021

    这么好的东西, 你们知道个软

  13. 岳云
    岳云 February 4, 2021

    当初看到Attributes 放弃了 java
    现在php 也有 ,确实部署 团队合作很重要。单作为个人开发看到这些累赘的语法糖 就很反感。

  14. miwu
    miwu December 28, 2020

    注解类是一个真正的类, 要和平常的类一样, 加上 use.

  15. shooke
    shooke December 25, 2020

    php发展了这么多年了,些年拼性能,这个无话可说。但现在随着项目越来越大,性能已经不是瓶颈php7性能已经可以了。管理、部署才是最重要的,java在大项目中成为首选,完全是因为生态圈太丰富,各种中间件,开源项目,部署工具。
    php的生态是它最大的软肋,现在虽然有swoole这么优秀的项目,但是部署和实施的成本还是偏高。php项目的依赖分为php本身所需依赖和composer,这是个很大的问题。
    看一看java、python,哪一个依赖不是自身语言编写的。php要解决的第一个问题就是依赖如何统一。玩c丰富php生态的人不是php的主力,而是后盾。用php编写代码的人才是php发展的主力。
    php本身的依赖建议直接放到php包中,直接支持,在迭代中发布。其次大力发动社区力量丰富php在部署、集成方面的生态。

  16. 路人甲
    路人甲 December 3, 2020

    感觉像java发展了,,,,

  17. noah
    noah November 29, 2020

    麻烦问一下各位大神,本地已经装好php8.1的环境了,鸟哥上面写的的注解类可以正常执行,然后注解的类加上命名空间之后调用就找不到注解类了,在调用注解的地方加上对应的命名空间也不行,这样应该怎么调用呢?

  18. 随机
    随机 November 27, 2020

    讲道理,语法有点ugly。感觉 php 的发展方向是不是有点跑偏了,国内好多需求很强烈的特性反而不支持。是不是因为 php 的决策层里国人的话语权不多

  19. yl
    yl November 2, 2020

    spring的注解是为了自动注入的吧 , 这个是获取参数值什么的用的吧 , 手动操作吧

  20. bao
    bao October 13, 2020

    这个功能很有用,看看java的spring,到处都是注解,用起来挺爽的

  21. Rea tang
    Rea tang October 12, 2020

    注解还是主要为AOP编程服务的,我觉得挺好。

  22. jee
    jee September 29, 2020

    要被go干翻了

  23. zhao
    zhao September 10, 2020

    虽然项目暂时用不到php8,但是一直关注php8的开发,对php8的注解很感兴趣,愿php越来越好,支持鸟哥

  24. 杨永安
    杨永安 September 4, 2020

    这样可以实现接口函数的 自动生成文档 或者权限判断

  25. mgzhenhong
    mgzhenhong August 17, 2020

    这是我一直期待的用法
    <?php
    <>
    class PermissionVerify{
    public function __construct($useless, $permissionCode) {
    if($Permission::verify(Auth::$currentUser, $permissionCode) Web::showError(‘Permission Denied’);
    }
    }

    //——————–

    function deleteArtical($articalId)
    {
    ….
    }

    不过用<>这个写法确实难看, 为什么不遵从phpdoc的写法用@或者@@来表达呢

    另外, 在Attribute的构造函数中, 不知道有没有办法拿到注解所在的类和方法, 拿不到的话, 谁知道是哪里调用的注解

  26. Colorful
    Colorful August 14, 2020

    鸟哥yaf什么时候支持 8.0

  27. luckyxu
    luckyxu July 29, 2020

    感觉没啥用啊,而且能执行的为啥写注释?完全将优雅给屏蔽掉了

  28. simon liu
    simon liu July 25, 2020

    为什么不采用@:
    @:See(“https://xxx/xxx/xxx.html”)

  29. Jie Zheng
    Jie Zheng July 20, 2020

    这应该是 PHP 中,最应该有的特性了,也非常非常有用。
    用法与 Hack 保持一致。
    对于大量使用 Reflection 的 lib,通过解析 doc_comment 实现,会担心性能,错误,定义奇怪的 syntax。
    这次他们终于迎来了春天。

  30. Denver Pearce
    Denver Pearce July 10, 2020

    PHP, there are only two ways to live your life. One is as though nothing is a miracle.

  31. wj008
    wj008 July 5, 2020

    <>
    function dummy($argument) {

    }
    这样 不应该报错才对啊。。。

    • wj008
      wj008 July 5, 2020


      Params(“Foo”, “argument”)
      See(“https://xxxxxxxx/xxxx/xxx.html”)
      Field(1)

      function dummy($argument) {

      }
      这样 不应该报错才对啊。。。

  32. Tony
    Tony July 2, 2020

    类似于C#、JAVA、Golang等的特性

  33. Bourne
    Bourne July 2, 2020

    确实丑,而且注解不利于代码阅读和调试

  34. sleep
    sleep June 27, 2020

    我觉得挺好的,没有必要吐槽符号如何如何, 如果想用着自己舒服可以成为改变这个语言的人,而不是在这里吐槽别人辛辛苦苦的设计成果.

  35. jam
    jam June 27, 2020

    大家都已习惯了注释,突然弄出一个这东西,看的我一脸懵逼,没懂,还觉得我以后还是会使用注释不会使用这个特性

  36. Alim
    Alim June 26, 2020

    我个人没感觉到太大的用途、

    • Alim
      Alim June 26, 2020

      个人感觉原来的备注挺好的

  37. church
    church June 22, 2020

    就因为”@”已经被用作抑制错误,就弄了个这么ugly的语法,真不如没有。不知道鸟哥介绍的是不是这个所谓“注解的”全部了,如果是这样的话,也太拙劣了,聊胜于无的东西。

  38. boobusy
    boobusy June 19, 2020

    真没什么卵用.太丑了, 可以在@符号做点文章. !@ 代表注解

  39. lianjiexue
    lianjiexue June 17, 2020

    太丑了,php明显跑偏

  40. Bo
    Bo June 16, 2020

    通俗易懂 就是这个写法有点尬,咋一看 以为是写的注释的,看着不太像注解

  41. 正
    June 15, 2020

    哈哈,写法确实有点丑啊

  42. ctfang
    ctfang June 15, 2020

    不用php自带也能实现相同的功能,只是更加方便了,特别对具有console命令的应用,例如数据库到模型类文件可以互相严格定义。

    什么时候可以解决一下:
    1,官方维护支持线程
    虽然线程扩展一直都用,但是都处于很尴尬的位置,停止维护,也没有人敢用。

    2,内存共享+强类型的map
    现有的扩展apc, shmop等,文件流共享,意义不大。
    比如常见web电商需求,提取评价的关键字,加载字典后,再转成树结构都要300MB内存左右,大点就算了,还无法共享使用。

    3,php-src自带的协程。
    swoole就实现了协程,至少证明技术上是可行的,但是swoole社区不稳定,知名公司,开源框架都和swoole闹翻了(有赞,SwooleDistributed,swoft,easyswoole等);

    • 李尔摩斯
      李尔摩斯 June 29, 2020

      同意!不然,感觉PHP前途渺茫,在性能要求很高的项目中直接被GO给干翻了

    • wj008
      wj008 July 3, 2020

      我觉得 php 引入协程 会对目前现有的基于php-fpm的发起一大挑战,协程一般是在常驻内存应用才能起到作用,而 php 的生态对常驻内存并不那么友好,而且 phper 不像javaer 一样 具备常驻内存开发的习惯和基础(phper 大多数没有释放内存习惯和变量会被污染的处理能力),这对于php环境来讲是一个灾难性的。
      除非有一天 vm 可以和java 或者 nodejs 一样 是常驻内存型的。但这个应该就是swoole 要做的工作,事实上两者是冲突的。很多人会在常驻内存环境中使用到非常驻内存的代码而造成系统不稳定,这样 swoole 就得背这个锅了。
      所以 如果说要开发协程 我觉得 应该是要从语法上重新定义一种语言,也就是完全放弃现有的 php 非常驻内存的生态,才有可能,比如 nodejs.

      • 拍黄瓜
        拍黄瓜 September 5, 2023

        即使是非常驻内存,PHP的速度也是够用的,要不然早被遗弃。事实上,这么多年过去了,PHP还生机勃勃积极发展。

        你的代码之所以慢,是具体生态的问题,往往让 PHP 背了锅。

        拿 WordPress 来说,有时慢到不可接受,原因是太多局部的过程被全局化,WP 整个生态主题、插件都有这毛病。不熟悉 WP 源代码,是找不到原因的,于是让 PHP 背锅。

  43. zhouyl
    zhouyl June 15, 2020

    为何不像java一样,使用 @Name @Name(Arguments) 这种格式,感觉更美观,并且编码过程中少敲不少字符

    • 魔王卷子
      魔王卷子 June 15, 2020

      因为有个抑制运算符已经将@使用了。所以不能用那个了。

    • 阿宝
      阿宝 July 21, 2020

      用 doctrine/annotations 注解包就可以,不过性能不咋样就是了

  44. nece001
    nece001 June 15, 2020

    注解终于要来了吗?

  45. Hawind
    Hawind June 13, 2020

    丑死了,发展了25年,什么都学JAVA的,空间用\就忍了,这个尼马要是写多了哪里还分的出正常代码还是注解,然后就是啥新特性,卧槽jdk5就有注解了,那么多《》《》《》好吗,至少让大家少打点符号,看着这个真心气炸了,诅咒决定用这个符号的人***。

    • laruence
      laruence June 13, 2020

      你的心情我可以理解,但可以适当淡定, IDE后续也会跟进修改,结合适当的配色,回降低对阅读正常代码影响的。

      • simon liu
        simon liu August 8, 2020

        强烈建议注解标识符改为@:
        单行注解:@:
        多行注解:@:{}

  46. ideaa
    ideaa June 12, 2020

    对我来说很有用,但是这语法简直丑出天际

    • SJ Chou
      SJ Chou June 15, 2020

      對於 Framework 的設計到是很有用,特別是 IoC/DI 這樣的架構,但是看到語法就有點想吐,想說 PHP8 為何不強化 getDocComment() 即可!?
      期待鳥哥下一篇 JIT 文章~多謝分享~

      • dvaknheo
        dvaknheo June 16, 2020

        现在大部分 PHP 的 IoC/DI 走偏了,没用上 PHP 的动态语言特性。
        为了解决 “调用方式不变,实现方式可变”这一问题,我的解决方案是使用可变单例。
        我写的框架 DuckPhp 有类似的用法
        MyClass::G()->foo(); // 输出 hello world
        MyClass::G(MySubClass::G()); //替换实例
        MyClass::G()->foo(); // 输出 你好。

        前后者调用方式都一样,实际上 第二句把 MyClass 的单例替换了。 导致后面输出为 MySubClass->foo()
        这个 ::G()-> 我也想替换成其他更简洁的方法,实在是替换不了了

  47. vic
    vic June 12, 2020

    也许很多人会问,这有什么卵用?

  48. mr
    mr June 12, 2020

    get新特性

  49. Grocker
    Grocker June 12, 2020

    提前get到了

Comments are closed.