站長資訊網
        最全最豐富的資訊網站

        php8的注解你了解多少?

        注解語法

        #[Route] #[Route()] #[Route("/path", ["get"])] #[Route(path: "/path", methods: ["get"])]

        其實語法跟實例化類非常相似,只是少了個 new 關鍵詞而已。

        要注意的是, 注解名不能是變量,只能是常量或常量表達式

        //實例化類 $route = new Route(path: "/path", methods: ["get"]);

        (path: "/path", methods: ["get"])php8 的新語法,在傳參的時候可以指定參數名,不按照形參的順序傳參。

        注解類作用范圍

        在定義注解類時,你可以使用內置注解類 #[Attribute] 定義注解類的作用范圍,也可以省略,由 PHP 動態地根據使用場景自動定義范圍

        注解作用范圍列表:

        • Attribute::TARGET_CLASS
        • Attribute::TARGET_FUNCTION
        • Attribute::TARGET_METHOD
        • Attribute::TARGET_PROPERTY
        • Attribute::TARGET_CLASS_CONSTANT
        • Attribute::TARGET_PARAMETER
        • Attribute::TARGET_ALL
        • Attribute::IS_REPEATABLE

        在使用時, #[Attribute] 等同于 #[Attribute(Attribute::TARGET_ALL)],為了方便,一般使用前者。

        1~7都很好理解,分別對應類、函數、類方法、類屬性、類常量、參數、所有,前6項可以使用 | 或運算符隨意組合,比如Attribute::TARGET_CLASS | Attribute::TARGET_FUNCTION。(Attribute::TARGET_ALL包含前6項,但并不包含 Attribute::IS_REPEATABLE)。

        Attribute::IS_REPEATABLE 設置該注解是否可以重復,比如:

        class IndexController {     #[Route('/index')]     #[Route('/index_alias')]     public function index()     {         echo "hello!world" . PHP_EOL;     } }

        如果沒有設置 Attribute::IS_REPEATABLERoute不允許使用兩次。

        上述提到的,如果沒有指定作用范圍,會由 PHP 動態地確定范圍,如何理解?舉例:

        <?php  class Deprecated {  }  class NewLogger {     public function newLogAction(): void     {         //do something     }      #[Deprecated('oldLogAction已廢棄,請使用newLogAction代替')]     public function oldLogAction(): void      {      } }  #[Deprecated('OldLogger已廢棄,請使用NewLogger代替')] class OldLogger {  }

        上述的自定義注解類 Deprecated 并沒有使用內置注解類 #[Attribute] 定義作用范圍,因此當它修飾類 OldLogger 時,它的作用范圍被動態地定義為 TARGET_CLASS。當它修飾方法 oldLogAction 時,它的作用范圍被動態地定義為 TARGET_METHOD一句話概括,就是修飾哪,它的作用范圍就在哪

        需要注意的是, 在設置了作用范圍之后,在編譯階段,除了內置注解類 #[Attribute],自定義的注解類是不會自動檢查作用范圍的。除非你使用反射類 ReflectionAttributenewInstance 方法。

        舉例:

        <?php  #[Attribute] function foo() {  }

        這里會報錯 Fatal error: Attribute "Attribute" cannot target function (allowed targets: class),因為內置注解類的作用范圍是 TARGET_CLASS,只能用于修飾類而不能是函數,因為內置注解類的作用范圍僅僅是 TARGET_CLASS,所以也不能重復修飾

        而自定義的注解類,在編譯時是不會檢查作用范圍的。

        <?php   #[Attribute(Attribute::TARGET_CLASS)] class A1 {  }  #[A1]  function foo() {}

        這樣是不會報錯的。那定義作用范圍有什么意義呢?看一個綜合實例。

        <?php   #[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_FUNCTION | Attribute::IS_REPEATABLE)] class Route {     protected $handler;      public function __construct(         public string $path = '',         public array $methods = []     ) {}      public function setHandler($handler): self     {         $this->handler = $handler;         return $this;     }      public function run()     {         call_user_func([new $this->handler->class, $this->handler->name]);     } }  class IndexController {     #[Route(path: "/index_alias", methods: ["get"])]     #[Route(path: "/index", methods: ["get"])]     public function index(): void     {         echo "hello!world" . PHP_EOL;     }      #[Route("/test")]     public function test(): void      {         echo "test" . PHP_EOL;     } }  class CLIRouter {     protected static array $routes = [];      public static function setRoutes(array $routes): void     {         self::$routes = $routes;     }      public static function match($path)     {         foreach (self::$routes as $route) {             if ($route->path == $path) {                 return $route;             }         }          die('404' . PHP_EOL);     } }  $controller = new ReflectionClass(IndexController::class); $methods = $controller->getMethods(ReflectionMethod::IS_PUBLIC);  $routes = []; foreach ($methods as $method) {     $attributes = $method->getAttributes(Route::class);      foreach ($attributes as $attribute) {         $routes[] = $attribute->newInstance()->setHandler($method);     } }  CLIRouter::setRoutes($routes); CLIRouter::match($argv[1])->run();
        php test.php /index php test.php /index_alias php test.php /test

        在使用 newInstance 時,定義的作用范圍才會生效,檢測注解類定義的作用范圍和實際修飾的范圍是否一致,其它場景并不檢測。

        注解命名空間

        <?php  namespace {     function dump_attributes($attributes) {         $arr = [];         foreach ($attributes as $attribute) {             $arr[] = ['name' => $attribute->getName(), 'args' => $attribute->getArguments()];         }         var_dump($arr);     } }  namespace DoctrineORMMapping {     class Entity {     } }  namespace DoctrineORMAttributes {     class Table {     } }  namespace Foo {     use DoctrineORMMappingEntity;     use DoctrineORMMapping as ORM;     use DoctrineORMAttributes;      #[Entity("imported class")]     #[ORMEntity("imported namespace")]     #[DoctrineORMMappingEntity("absolute from namespace")]     #[Entity("import absolute from global")]     #[AttributesTable()]     function foo() {     } }  namespace {     class Entity {}      dump_attributes((new ReflectionFunction('Foofoo'))->getAttributes()); }  //輸出:  array(5) {   [0]=>   array(2) {     ["name"]=>     string(27) "DoctrineORMMappingEntity"     ["args"]=>     array(1) {       [0]=>       string(14) "imported class"     }   }   [1]=>   array(2) {     ["name"]=>     string(27) "DoctrineORMMappingEntity"     ["args"]=>     array(1) {       [0]=>       string(18) "imported namespace"     }   }   [2]=>   array(2) {     ["name"]=>     string(27) "DoctrineORMMappingEntity"     ["args"]=>     array(1) {       [0]=>       string(23) "absolute from namespace"     }   }   [3]=>   array(2) {     ["name"]=>     string(6) "Entity"     ["args"]=>     array(1) {       [0]=>       string(27) "import absolute from global"     }   }   [4]=>   array(2) {     ["name"]=>     string(29) "DoctrineORMAttributesTable"     ["args"]=>     array(0) {     }   } }

        跟普通類的命名空間一致。

        其它要注意的一些問題

        • 不能在注解類參數列表中使用 unpack 語法。
        <?php  class IndexController {     #[Route(...["/index", ["get"]])]     public function index()     {      } }

        雖然在詞法解析階段是通過的,但是在編譯階段會拋出錯誤。

        • 在使用注解時可以換行
        <?php   class IndexController {     #[Route(         "/index",         ["get"]     )]     public function index()     {      } }
        • 注解可以成組使用
        <?php  class IndexController {     #[Route(         "/index",         ["get"]     ), Other, Another]     public function index()     {      } }
        • 注解的繼承

        注解是可以繼承的,也可以覆蓋。

        <?php  class C1 {     #[A1]     public function foo() { } }  class C2 extends C1 {     public function foo() { } }  class C3 extends C1 {     #[A1]     public function bar() { } }  $ref = new ReflectionClass(C1::class); print_r(array_map(fn ($a) => $a->getName(), $ref->getMethod('foo')->getAttributes()));  $ref = new ReflectionClass(C2::class); print_r(array_map(fn ($a) => $a->getName(), $ref->getMethod('foo')->getAttributes()));  $ref = new ReflectionClass(C3::class); print_r(array_map(fn ($a) => $a->getName(), $ref->getMethod('foo')->getAttributes()));

        C3 繼承了 C1foo 方法,也繼承了 foo 的注解。而 C2 覆蓋了 C1foo 方法,因此注解也就不存在了。

        推薦學習:《PHP8教程》

        贊(0)
        分享到: 更多 (0)
        網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
        主站蜘蛛池模板: 国产精品白丝AV网站| 久久se精品一区二区| 99re这里只有精品6| 香蕉99久久国产综合精品宅男自| 国产99re在线观看只有精品| 无码国内精品人妻少妇 | 久久五月精品中文字幕| 精品国产一区二区三区免费| 无码精品久久久久久人妻中字 | 国产成人精品免费视频大全麻豆| 中文字幕乱码中文乱码51精品 | 国产精品毛片一区二区三区| 亚洲线精品一区二区三区| 精品亚洲成α人无码成α在线观看| 老司机91精品网站在线观看| 国产成人精品久久免费动漫| 国产精品天干天干综合网| 亚洲精品无码久久一线| 少妇亚洲免费精品| 久久精品国产精品亚洲下载| 国产小呦泬泬99精品| 国产精品青青在线观看爽香蕉| 久久青青草原精品影院| 国产精品久久免费| 国产成人精品精品欧美| 动漫精品专区一区二区三区不卡| 1024国产欧美日韩精品| 国产在线精品一区二区在线观看| 久久精品国产99久久久| 无码国内精品人妻少妇| 无码国产精品一区二区免费vr| 亚洲国产精品无码AAA片| 亚洲精品宾馆在线精品酒店| 亚洲欧美日韩国产一区二区三区精品 | 久久精品人成免费| 久久精品人人槡人妻人人玩AV | 精品一区二区三区免费| 国产精品亚洲午夜一区二区三区| 国产精品福利一区二区久久| 久久99精品国产一区二区三区| 国产在视频线精品视频二代|