Skip to content

Commit a7908c2

Browse files
beberleikooldev
andcommitted
Add Attributes
Co-authored-by: Martin Schröder <[email protected]>
1 parent 970ac28 commit a7908c2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+2351
-60
lines changed
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
--TEST--
2+
Attributes can be placed on all supported elements.
3+
--FILE--
4+
<?php
5+
6+
<<A1(1)>>
7+
class Foo
8+
{
9+
<<A1(2)>>
10+
public const FOO = 'foo';
11+
12+
<<A1(3)>>
13+
public $x;
14+
15+
<<A1(4)>>
16+
public function foo(<<A1(5)>> $a, <<A1(6)>> $b) { }
17+
}
18+
19+
$object = new <<A1(7)>> class () { };
20+
21+
<<A1(8)>>
22+
function f1() { }
23+
24+
$f2 = <<A1(9)>> function () { };
25+
26+
$f3 = <<A1(10)>> fn () => 1;
27+
28+
$ref = new \ReflectionClass(Foo::class);
29+
30+
$sources = [
31+
$ref,
32+
$ref->getReflectionConstant('FOO'),
33+
$ref->getProperty('x'),
34+
$ref->getMethod('foo'),
35+
$ref->getMethod('foo')->getParameters()[0],
36+
$ref->getMethod('foo')->getParameters()[1],
37+
new \ReflectionObject($object),
38+
new \ReflectionFunction('f1'),
39+
new \ReflectionFunction($f2),
40+
new \ReflectionFunction($f3)
41+
];
42+
43+
foreach ($sources as $r) {
44+
$attr = $r->getAttributes();
45+
var_dump(get_class($r), count($attr));
46+
47+
foreach ($attr as $a) {
48+
var_dump($a->getName(), $a->getArguments());
49+
}
50+
51+
echo "\n";
52+
}
53+
54+
?>
55+
--EXPECT--
56+
string(15) "ReflectionClass"
57+
int(1)
58+
string(2) "A1"
59+
array(1) {
60+
[0]=>
61+
int(1)
62+
}
63+
64+
string(23) "ReflectionClassConstant"
65+
int(1)
66+
string(2) "A1"
67+
array(1) {
68+
[0]=>
69+
int(2)
70+
}
71+
72+
string(18) "ReflectionProperty"
73+
int(1)
74+
string(2) "A1"
75+
array(1) {
76+
[0]=>
77+
int(3)
78+
}
79+
80+
string(16) "ReflectionMethod"
81+
int(1)
82+
string(2) "A1"
83+
array(1) {
84+
[0]=>
85+
int(4)
86+
}
87+
88+
string(19) "ReflectionParameter"
89+
int(1)
90+
string(2) "A1"
91+
array(1) {
92+
[0]=>
93+
int(5)
94+
}
95+
96+
string(19) "ReflectionParameter"
97+
int(1)
98+
string(2) "A1"
99+
array(1) {
100+
[0]=>
101+
int(6)
102+
}
103+
104+
string(16) "ReflectionObject"
105+
int(1)
106+
string(2) "A1"
107+
array(1) {
108+
[0]=>
109+
int(7)
110+
}
111+
112+
string(18) "ReflectionFunction"
113+
int(1)
114+
string(2) "A1"
115+
array(1) {
116+
[0]=>
117+
int(8)
118+
}
119+
120+
string(18) "ReflectionFunction"
121+
int(1)
122+
string(2) "A1"
123+
array(1) {
124+
[0]=>
125+
int(9)
126+
}
127+
128+
string(18) "ReflectionFunction"
129+
int(1)
130+
string(2) "A1"
131+
array(1) {
132+
[0]=>
133+
int(10)
134+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
--TEST--
2+
Attributes: Example from Attributes RFC
3+
--FILE--
4+
<?php
5+
// https://wiki.php.net/rfc/attributes_v2#attribute_syntax
6+
namespace My\Attributes {
7+
use PhpAttribute;
8+
9+
<<PhpAttribute>>
10+
class SingleArgument {
11+
public $argumentValue;
12+
13+
public function __construct($argumentValue) {
14+
$this->argumentValue = $argumentValue;
15+
}
16+
}
17+
}
18+
19+
namespace {
20+
use My\Attributes\SingleArgument;
21+
22+
<<SingleArgument("Hello World")>>
23+
class Foo {
24+
}
25+
26+
$reflectionClass = new \ReflectionClass(Foo::class);
27+
$attributes = $reflectionClass->getAttributes();
28+
29+
var_dump($attributes[0]->getName());
30+
var_dump($attributes[0]->getArguments());
31+
var_dump($attributes[0]->newInstance());
32+
}
33+
?>
34+
--EXPECTF--
35+
string(28) "My\Attributes\SingleArgument"
36+
array(1) {
37+
[0]=>
38+
string(11) "Hello World"
39+
}
40+
object(My\Attributes\SingleArgument)#3 (1) {
41+
["argumentValue"]=>
42+
string(11) "Hello World"
43+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
--TEST--
2+
Attributes can deal with AST nodes.
3+
--FILE--
4+
<?php
5+
6+
define('V1', strtoupper(php_sapi_name()));
7+
8+
<<A1([V1 => V1])>>
9+
class C1
10+
{
11+
public const BAR = 'bar';
12+
}
13+
14+
$ref = new \ReflectionClass(C1::class);
15+
$attr = $ref->getAttributes();
16+
var_dump(count($attr));
17+
18+
$args = $attr[0]->getArguments();
19+
var_dump(count($args), $args[0][V1] === V1);
20+
21+
echo "\n";
22+
23+
<<A1(V1, 1 + 2, C1::class)>>
24+
class C2 { }
25+
26+
$ref = new \ReflectionClass(C2::class);
27+
$attr = $ref->getAttributes();
28+
var_dump(count($attr));
29+
30+
$args = $attr[0]->getArguments();
31+
var_dump(count($args));
32+
var_dump($args[0] === V1);
33+
var_dump($args[1] === 3);
34+
var_dump($args[2] === C1::class);
35+
36+
echo "\n";
37+
38+
<<A1(self::FOO, C1::BAR)>>
39+
class C3
40+
{
41+
private const FOO = 'foo';
42+
}
43+
44+
$ref = new \ReflectionClass(C3::class);
45+
$attr = $ref->getAttributes();
46+
var_dump(count($attr));
47+
48+
$args = $attr[0]->getArguments();
49+
var_dump(count($args));
50+
var_dump($args[0] === 'foo');
51+
var_dump($args[1] === C1::BAR);
52+
53+
echo "\n";
54+
55+
<<ExampleWithShift(4 >> 1)>>
56+
class C4 {}
57+
$ref = new \ReflectionClass(C4::class);
58+
var_dump($ref->getAttributes()[0]->getArguments());
59+
60+
echo "\n";
61+
62+
<<PhpAttribute>>
63+
class C5
64+
{
65+
public function __construct() { }
66+
}
67+
68+
$ref = new \ReflectionFunction(<<C5(MissingClass::SOME_CONST)>> function () { });
69+
$attr = $ref->getAttributes();
70+
var_dump(count($attr));
71+
72+
try {
73+
$attr[0]->getArguments();
74+
} catch (\Error $e) {
75+
var_dump($e->getMessage());
76+
}
77+
78+
try {
79+
$attr[0]->newInstance();
80+
} catch (\Error $e) {
81+
var_dump($e->getMessage());
82+
}
83+
84+
?>
85+
--EXPECT--
86+
int(1)
87+
int(1)
88+
bool(true)
89+
90+
int(1)
91+
int(3)
92+
bool(true)
93+
bool(true)
94+
bool(true)
95+
96+
int(1)
97+
int(2)
98+
bool(true)
99+
bool(true)
100+
101+
array(1) {
102+
[0]=>
103+
int(2)
104+
}
105+
106+
int(1)
107+
string(30) "Class 'MissingClass' not found"
108+
string(30) "Class 'MissingClass' not found"
109+
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
--TEST--
2+
Resolve attribute names
3+
--FILE--
4+
<?php
5+
function dump_attributes($attributes) {
6+
$arr = [];
7+
foreach ($attributes as $attribute) {
8+
$arr[] = ['name' => $attribute->getName(), 'args' => $attribute->getArguments()];
9+
}
10+
var_dump($arr);
11+
}
12+
13+
namespace Doctrine\ORM\Mapping {
14+
class Entity {
15+
}
16+
}
17+
18+
namespace Doctrine\ORM\Attributes {
19+
class Table {
20+
}
21+
}
22+
23+
namespace Foo {
24+
use Doctrine\ORM\Mapping\Entity;
25+
use Doctrine\ORM\Mapping as ORM;
26+
use Doctrine\ORM\Attributes;
27+
28+
<<Entity("imported class")>>
29+
<<ORM\Entity("imported namespace")>>
30+
<<\Doctrine\ORM\Mapping\Entity("absolute from namespace")>>
31+
<<\Entity("import absolute from global")>>
32+
<<Attributes\Table()>>
33+
function foo() {
34+
}
35+
}
36+
37+
namespace {
38+
class Entity {}
39+
40+
dump_attributes((new ReflectionFunction('Foo\foo'))->getAttributes());
41+
}
42+
?>
43+
--EXPECTF--
44+
array(5) {
45+
[0]=>
46+
array(2) {
47+
["name"]=>
48+
string(27) "Doctrine\ORM\Mapping\Entity"
49+
["args"]=>
50+
array(1) {
51+
[0]=>
52+
string(14) "imported class"
53+
}
54+
}
55+
[1]=>
56+
array(2) {
57+
["name"]=>
58+
string(27) "Doctrine\ORM\Mapping\Entity"
59+
["args"]=>
60+
array(1) {
61+
[0]=>
62+
string(18) "imported namespace"
63+
}
64+
}
65+
[2]=>
66+
array(2) {
67+
["name"]=>
68+
string(27) "Doctrine\ORM\Mapping\Entity"
69+
["args"]=>
70+
array(1) {
71+
[0]=>
72+
string(23) "absolute from namespace"
73+
}
74+
}
75+
[3]=>
76+
array(2) {
77+
["name"]=>
78+
string(6) "Entity"
79+
["args"]=>
80+
array(1) {
81+
[0]=>
82+
string(27) "import absolute from global"
83+
}
84+
}
85+
[4]=>
86+
array(2) {
87+
["name"]=>
88+
string(29) "Doctrine\ORM\Attributes\Table"
89+
["args"]=>
90+
array(0) {
91+
}
92+
}
93+
}

0 commit comments

Comments
 (0)