PHP8官方注解实战

PHP8在前几天开始支持注解了,我们可以体验下,RFC在这里

注解的使用在很多的PHP框架里面已经具备了,所以我们不对注解做过多的解释,我们直接通过一个例子来看看注解可以怎么玩。

我们打算通过注解来实现一个功能:只要这个类被打上了Bean注解,那么我们就需要对这个类进行实例化,并且放在DI容器里面。

首先创建一个beans.php文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php

namespace App;

<<\Bean>>
class Foo
{
<<Value(1.1)>>
public $x;

<<Value(1.2)>>
public $y;
}

<<\Bean>>
class Bar
{
<<Value('2')>>
public $x;
}

<<\Bean>>
class Tar
{
<<Value(3)>>
public $x;
}

这里有一个地方和民间版本的注解doctrine/annotations有点区别。在民间版本里面,注解是写在PHP注释里面的,而官方支持的注解直接定义了新的语法(即注解写在了<< >>里面)。

然后实现扫描的功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php

require 'beans.php';

$classes = get_declared_classes();

$container = [];

$scanNamespace = 'App';
$scanAnno = 'Bean';

foreach ($classes as $key => $class) {
if (str_contains($class, $scanNamespace)) {
$refClass = new \ReflectionClass($class);
$classAttrs = $refClass->getAttributes();
foreach ($classAttrs as $key => $classAttr) {
$value = $classAttr->getName();
if ($value === $scanAnno) {
$refProperties = $refClass->getProperties();
$obj = $refClass->newInstance();
foreach ($refProperties as $key => $refProperty) {
$refProperty = $refClass->getProperty($refProperty->getName());
$propertyAttrs = $refProperty->getAttributes();
$value = $propertyAttrs[0]->getArguments();
$refProperty->setValue($obj, $value[0]);
$container[$class] = $obj;
}
}
}
}
}

var_dump($container);

执行结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
array(3) {
["App\Foo"]=>
object(App\Foo)#5 (2) {
["x"]=>
float(1.1)
["y"]=>
float(1.2)
}
["App\Bar"]=>
object(App\Bar)#4 (1) {
["x"]=>
string(1) "2"
}
["App\Tar"]=>
object(App\Tar)#1 (1) {
["x"]=>
int(3)
}
}

我们可以测试一下,把Tar类的Bean注解删除,那么就不会对这个类进行实例化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php

namespace App;

<<\Bean>>
class Foo
{
<<Value(1.1)>>
public $x;

<<Value(1.2)>>
public $y;
}

<<\Bean>>
class Bar
{
<<Value('2')>>
public $x;
}

class Tar
{
<<Value(3)>>
public $x;
}

执行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
array(2) {
["App\Foo"]=>
object(App\Foo)#5 (2) {
["x"]=>
float(1.1)
["y"]=>
float(1.2)
}
["App\Bar"]=>
object(App\Bar)#4 (1) {
["x"]=>
string(1) "2"
}
}