Sejauh manakah anda tahu tentang anotasi php8?

藏色散人
Lepaskan: 2023-02-17 12:08:01
ke hadapan
4896 orang telah melayarinya

Sintaks anotasi

#[Route]
#[Route()]
#[Route("/path", ["get"])]
#[Route(path: "/path", methods: ["get"])]
Salin selepas log masuk

Malah, sintaks sangat serupa dengan kelas instantiated, kecuali kata kunci new tiada .

Perlu diambil perhatian bahawa nama anotasi tidak boleh menjadi pembolehubah, tetapi hanya boleh menjadi ungkapan malar atau malar

//实例化类
$route = new Route(path: "/path", methods: ["get"]);
Salin selepas log masuk

(path: "/path", methods: ["get"]) ialah sintaks baharu daripada php8 , anda boleh menentukan nama parameter apabila menghantar parameter, dan jangan lulus parameter dalam susunan parameter formal.

Skop kelas anotasi

Apabila mentakrifkan kelas anotasi, anda boleh menggunakan kelas anotasi terbina dalam #[Attribute] untuk menentukan skop kelas anotasi atau anda boleh meninggalkannya, ditentukan secara dinamik oleh PHP Gunakan senario untuk menentukan julat secara automatik .

Senarai skop anotasi:

  • Atribut::TARGET_CLASS
  • Atribut::TARGET_FUNCTION
  • Atribut::TARGET_METHOD>
  • Atribut::TARGET_CLASS_CONSTANT
  • Attribute::TARGET_PARAMETER
  • Atribut::TARGET_ALL
  • IS_REPETribut:
  • digunakan,
  • bersamaan dengan
  • Untuk kemudahan, yang pertama biasanya digunakan.
1~7 mudah difahami dan sepadan dengan kelas, fungsi, kaedah kelas, atribut kelas, pemalar kelas, parameter, dan semuanya masing-masing 6 item pertama boleh digabungkan sesuka hati menggunakan #[Attribute] atau operator , seperti #[Attribute(Attribute::TARGET_ALL)]. (

termasuk 6 item pertama, tetapi tidak termasuk |Attribute::TARGET_CLASS | Attribute::TARGET_FUNCTION). Attribute::TARGET_ALLAttribute::IS_REPEATABLE Tetapkan sama ada anotasi boleh diulang, contohnya:

Jika Attribute::IS_REPEATABLE tidak ditetapkan,

tidak dibenarkan digunakan dua kali.
class IndexController
{
    #[Route('/index')]
    #[Route('/index_alias')]
    public function index()
    {
        echo "hello!world" . PHP_EOL;
    }
}
Salin selepas log masuk

Seperti yang dinyatakan di atas, jika skop tidak dinyatakan, PHP akan menentukan skop secara dinamik. Bagaimana anda memahaminya? Contoh: Attribute::IS_REPEATABLERoute

Kelas anotasi tersuai yang disebutkan di atas

tidak menggunakan kelas anotasi terbina dalam

untuk mentakrifkan skop, jadi apabila ia mengubah suai kelas
<?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
{

}
Salin selepas log masuk
, skopnya secara dinamik Ditakrifkan sebagai

. Apabila ia mengubah suai kaedah Deprecated, skopnya ditakrifkan secara dinamik sebagai #[Attribute]. OldLoggerDalam satu ayat, di mana sahaja ia diubah suai, skopnya juga adaTARGET_CLASSoldLogActionTARGET_METHODPerlu diingatkan bahawa selepas menetapkan skop, semasa fasa penyusunan, sebagai tambahan kepada bina- dalam kelas anotasi , kelas anotasi tersuai tidak akan menyemak skop secara automatik. Melainkan anda menggunakan kaedah

kelas refleksi

. #[Attribute]ReflectionAttribute Contoh: newInstance

Ralat akan dilaporkan di sini

, kerana skop kelas anotasi terbina dalam ialah

dan hanya boleh digunakan untuk ubah suai kelas dan bukan fungsi
<?php

#[Attribute]
function foo()
{

}
Salin selepas log masuk
Oleh kerana skop kelas anotasi terbina dalam hanyalah

, jadi Fatal error: Attribute "Attribute" cannot target function (allowed targets: class) tidak boleh diubah suai berulang kali. TARGET_CLASSKelas anotasi tersuai tidak akan menyemak skop semasa penyusunan. TARGET_CLASS

Dengan cara ini tiada ralat akan dilaporkan. Jadi apa gunanya menentukan skop? Mari kita lihat contoh yang komprehensif.

<?php 

#[Attribute(Attribute::TARGET_CLASS)]
class A1
{

}

#[A1] 
function foo() {}
Salin selepas log masuk

Apabila menggunakan

, skop yang ditentukan akan berkuat kuasa sama ada skop yang ditakrifkan oleh kelas anotasi adalah konsisten dengan skop yang diubah suai sebenar tidak akan diuji.
<?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();
Salin selepas log masuk
php test.php /index
php test.php /index_alias
php test.php /test
Salin selepas log masuk
Ruang nama anotasi

newInstance

adalah sama dengan ruang nama kelas biasa.

Beberapa isu lain yang perlu diberi perhatian
<?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) {
    }
  }
}
Salin selepas log masuk

Anda tidak boleh

menggunakan sintaks
    dalam senarai parameter kelas anotasi.
  • unpackWalaupun ia lulus dalam peringkat penghuraian leksikal, ralat akan dilemparkan dalam peringkat penyusunan.
<?php

class IndexController
{
    #[Route(...["/index", ["get"]])]
    public function index()
    {

    }
}
Salin selepas log masuk
Anda boleh membalut baris apabila menggunakan anotasi

  • Anotasi boleh digunakan dalam kumpulan
<?php 

class IndexController
{
    #[Route(
        "/index",
        ["get"]
    )]
    public function index()
    {

    }
}
Salin selepas log masuk
  • Warisan anotasi
<?php

class IndexController
{
    #[Route(
        "/index",
        ["get"]
    ), Other, Another]
    public function index()
    {

    }
}
Salin selepas log masuk
    Anotasi boleh diwarisi atau ditindih.

mewarisi kaedah

<?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()));
Salin selepas log masuk
dan juga mewarisi anotasi

. Dan C3 merangkumi kaedah C1 foo, jadi anotasi tidak wujud. fooC2C1Pembelajaran yang disyorkan: "fooTutorial PHP8

"

Atas ialah kandungan terperinci Sejauh manakah anda tahu tentang anotasi php8?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Label berkaitan:
sumber:segmentfault.com
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan