検索
ホームページバックエンド開発PHP8php8 アノテーションについてどれくらい知っていますか?

アノテーション構文

#[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
  • 属性::TARGET_PROPERTY
  • 属性::TARGET_CLASS_CONSTANT
  • 属性::TARGET_PARAMETER
  • 属性::TARGET_ALL
  • 属性::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_REPEATABLE が設定されていない場合、ルート 重複使用はできません。

上で述べたように、スコープが指定されていない場合、PHP が動的にスコープを決定します。例:

<?php class Deprecated
{

}

class NewLogger
{
    public function newLogAction(): void
    {
        //do something
    }

    #[Deprecated(&#39;oldLogAction已废弃,请使用newLogAction代替&#39;)]
    public function oldLogAction(): void 
    {

    }
}

#[Deprecated(&#39;OldLogger已废弃,请使用NewLogger代替&#39;)]
class OldLogger
{

}

上記のカスタム アノテーション クラス Deprecated は、スコープの定義に組み込みアノテーション クラス #[Attribute] を使用しません。クラス OldLogger を変更し、そのスコープは TARGET_CLASS として動的に定義されます。メソッド oldLogAction を変更すると、そのスコープは TARGET_METHOD として動的に定義されます。 一言で言えば、変更された場合、そのスコープは

スコープを設定した後、コンパイル段階で組み込みのスコープに加えて、アノテーション クラス #[属性]、カスタム アノテーション クラスはスコープを自動的にチェックしません。リフレクション クラス ReflectionAttributenewInstance メソッドを使用しない限り。

例:

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

}

ここでエラーが報告されます致命的エラー: 属性 "属性" は関数 (許可されたターゲット: クラス) をターゲットにできません 、組み込みアノテーション クラスの役割 スコープは 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 = &#39;&#39;,
        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[] = [&#39;name&#39; => $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) {
    }
  }
}

は、通常のクラスの名前空間と一致します。

注意すべきその他の問題

  • アノテーション クラス パラメーター リストで 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 のアノテーションも継承します。また、C2C1foo メソッドをカバーしているため、アノテーションは存在しません。

推奨学習: 「

PHP8 チュートリアル

以上がphp8 アノテーションについてどれくらい知っていますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明
この記事はsegmentfaultで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

Dreamweaver Mac版

Dreamweaver Mac版

ビジュアル Web 開発ツール

MantisBT

MantisBT

Mantis は、製品の欠陥追跡を支援するために設計された、導入が簡単な Web ベースの欠陥追跡ツールです。 PHP、MySQL、Web サーバーが必要です。デモおよびホスティング サービスをチェックしてください。

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

Eclipse を SAP NetWeaver アプリケーション サーバーと統合します。

VSCode Windows 64 ビットのダウンロード

VSCode Windows 64 ビットのダウンロード

Microsoft によって発売された無料で強力な IDE エディター

PhpStorm Mac バージョン

PhpStorm Mac バージョン

最新(2018.2.1)のプロフェッショナル向けPHP統合開発ツール