Maison> développement back-end> PHP8> le corps du texte

Que savez-vous des annotations php8 ?

藏色散人
Libérer: 2023-02-17 12:08:01
avant
4730 Les gens l'ont consulté

syntaxe d'annotation

#[Route] #[Route()] #[Route("/path", ["get"])] #[Route(path: "/path", methods: ["get"])]
Copier après la connexion

En fait, la syntaxe est très similaire à la classe instanciée, sauf que le mot-clénewest manquant.new关键词而已。

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

//实例化类 $route = new Route(path: "/path", methods: ["get"]);
Copier après la connexion

(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; } }
Copier après la connexion

如果没有设置Attribute::IS_REPEATABLERoute不允许使用两次。

上述提到的,如果没有指定作用范围,会由 PHP 动态地确定范围,如何理解?举例:


         
Copier après la connexion

上述的自定义注解类Deprecated并没有使用内置注解类#[Attribute]定义作用范围,因此当它修饰类OldLogger时,它的作用范围被动态地定义为TARGET_CLASS。当它修饰方法oldLogAction时,它的作用范围被动态地定义为TARGET_METHOD一句话概括,就是修饰哪,它的作用范围就在哪

需要注意的是, 在设置了作用范围之后,在编译阶段,除了内置注解类#[Attribute],自定义的注解类是不会自动检查作用范围的。除非你使用反射类ReflectionAttributenewInstance方法。

举例:


         
Copier après la connexion

这里会报错Fatal error: Attribute "Attribute" cannot target function (allowed targets: class),因为内置注解类的作用范围是TARGET_CLASS,只能用于修饰类而不能是函数,因为内置注解类的作用范围仅仅是TARGET_CLASS,所以也不能重复修饰

而自定义的注解类,在编译时是不会检查作用范围的。


         
Copier après la connexion

这样是不会报错的。那定义作用范围有什么意义呢?看一个综合实例。

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();
Copier après la connexion
php test.php /index php test.php /index_alias php test.php /test
Copier après la connexion

在使用newInstance时,定义的作用范围才会生效,检测注解类定义的作用范围和实际修饰的范围是否一致,其它场景并不检测。

注解命名空间

 $attribute->getName(), 'args' => $attribute->getArguments()]; } var_dump($arr); } } namespace Doctrine\ORM\Mapping { class Entity { } } namespace Doctrine\ORM\Attributes { class Table { } } namespace Foo { use Doctrine\ORM\Mapping\Entity; use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Attributes; #[Entity("imported class")] #[ORM\Entity("imported namespace")] #[\Doctrine\ORM\Mapping\Entity("absolute from namespace")] #[\Entity("import absolute from global")] #[Attributes\Table()] function foo() { } } namespace { class Entity {} dump_attributes((new ReflectionFunction('Foo\foo'))->getAttributes()); } //输出: array(5) { [0]=> array(2) { ["name"]=> string(27) "Doctrine\ORM\Mapping\Entity" ["args"]=> array(1) { [0]=> string(14) "imported class" } } [1]=> array(2) { ["name"]=> string(27) "Doctrine\ORM\Mapping\Entity" ["args"]=> array(1) { [0]=> string(18) "imported namespace" } } [2]=> array(2) { ["name"]=> string(27) "Doctrine\ORM\Mapping\Entity" ["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) "Doctrine\ORM\Attributes\Table" ["args"]=> array(0) { } } }
Copier après la connexion

跟普通类的命名空间一致。

其它要注意的一些问题

  • 不能在注解类参数列表中使用unpack语法。

         
Copier après la connexion

虽然在词法解析阶段是通过的,但是在编译阶段会抛出错误。

  • 在使用注解时可以换行

         
Copier après la connexion
  • 注解可以成组使用

         
Copier après la connexion
  • 注解的继承

注解是可以继承的,也可以覆盖。

 $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()));
Copier après la connexion

C3继承了C1foo方法,也继承了foo的注解。而C2覆盖了C1foo

Il est à noter que le nom de l'annotation ne peut pas être une variable, mais ne peut être qu'une constante ou une expression constante
rrreee

(path: "/path", méthodes: ["get "])est la nouvelle syntaxe dephp8. Lors de la transmission de paramètres, vous pouvez spécifier des noms de paramètres au lieu de transmettre les paramètres dans l'ordre des paramètres formels.Portée de la classe d'annotation

Lors de la définition d'une classe d'annotation, vous pouvez utiliser la classe d'annotation intégrée #[Attribut]pour définir la portée de la classe d'annotation, ou vous pouvez l'omettre PHP l'ajustera dynamiquement en fonction des scénarios d'utilisation pour définir automatiquement les portées. Liste de portée d'annotation :
  • Attribut ::TARGET_CLASS
  • Attribut ::TARGET_FUNCTION
  • Attribut ::TARGET_METHOD
  • Attribut : TARGET_PROPERTY
  • Attribut ::TARGET_CLASS_CONSTANT
  • Attribut ::TARGET_PARAMETER
  • Attribut ::TARGET_ALL
  • Attribut ::IS_REPEATABLE
  • Lorsqu'il est utilisé, #[Attribute]est équivalent à #[Attribute(Attribute::TARGET_ALL)]Pour plus de commodité, le premier est généralement utilisé.
    1~7 sont tous faciles à comprendre. Ils correspondent aux classes, fonctions, méthodes de classe, attributs de classe, constantes de classe, paramètres et tout le reste. Les 6 premiers éléments peuvent être combinés à volonté en utilisant |<.> ou des opérateurs , tels que Attribute::TARGET_CLASS | Attribute::TARGET_FUNCTION. ( Attribute::TARGET_ALLcontient les 6 premiers éléments, mais n'inclut pasAttribute::IS_REPEATABLE). Attribute::IS_REPEATABLEDéfinissez si l'annotation peut être répétée, par exemple : rrreeeSi Attribute::IS_REPEATABLEn'est pas défini, Routen'est pas autorisé à utiliser deux fois. Comme mentionné ci-dessus, si la portée n'est pas spécifiée, PHP déterminera dynamiquement la portée. Comment comprenez-vous cela ? Exemple : rrreeeLa classe d'annotation personnalisée Obsolètementionnée ci-dessus n'utilise pas la classe d'annotation intégrée #[Attribute]pour définir la portée, donc lorsqu'elle modifie le classe OldLogger, sa portée est définie dynamiquement comme TARGET_CLASS. Lorsqu'il modifie la méthode oldLogAction, sa portée est définie dynamiquement comme TARGET_METHOD. Pour le résumer en une phrase, partout où il sera modifié, sa portée sera là Il est à noter qu'après avoir défini la portée, lors de la phase de compilation, en plus du construit -dans la classe d'annotation#[Attribut], les classes d'annotations personnalisées ne vérifieront pas automatiquement la portée. Sauf si vous utilisez la méthodenewInstancede la classe de réflexionReflectionAttribute.Exemple : rrreeeL'erreur Erreur fatale : l'attribut "Attribut" ne peut pas cibler la fonction (cibles autorisées : classe)sera signalée ici, car la portée de l'annotation intégrée la classe est TARGET_CLASS, ne peut être utilisée que pour modifier des classes, pas des fonctions Étant donné que la portée de la classe d'annotation intégrée est uniquementTARGET_CLASS, elle ne peut pas être modifiée. à plusieurs reprises. Les classes d'annotation personnalisées ne vérifieront pas la portée lors de la compilation. rrreeeDe cette façon, aucune erreur ne sera signalée. Alors à quoi ça sert de définir le périmètre ? Regardons un exemple complet. rrreeerrreeeLa portée définie ne prendra effet que lors de l'utilisation de newInstance. Il est vérifié si la portée définie par la classe d'annotation est cohérente avec la portée réelle modifiée. L'espace de noms d'annotation rrreee est le même que l'espace de noms des classes ordinaires. Quelques autres problèmes auxquels il faut prêter attention
    • Vous ne pouvez pasutiliser la syntaxeunpackdans la liste des paramètres de la classe d'annotation.
    rrreeeBien que cela passe à l'étape d'analyse lexicale, une erreur sera générée lors de l'étape de compilation.
    • Les lignes peuvent être renvoyées à la ligne lors de l'utilisation d'annotations
    rrreee
    • Les annotations peuvent être utilisées en groupe
    rrreee
    • Héritage des annotations
    Les annotations peuvent être héritées et remplacées. rrreee C3hérite de la méthode foode C1et hérite également des annotations de foo. Et C2couvre la méthode foode C1, donc l'annotation n'existe pas. Apprentissage recommandé : "Tutoriel PHP8"

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:segmentfault.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!