Skip to content

Commit 4cc905c

Browse files
beberleikooldev
andcommitted
Add Attributes
Co-authored-by: Martin Schröder <m.schroeder2007@gmail.com>
1 parent cebe750 commit 4cc905c

Some content is hidden

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

45 files changed

+2311
-54
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: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
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 Foo {
19+
use Doctrine\ORM\Mapping\Entity;
20+
use Doctrine\ORM\Mapping as ORM;
21+
22+
<<Entity("imported class")>>
23+
<<ORM\Entity("imported namespace")>>
24+
<<\Doctrine\ORM\Mapping\Entity("absolute from namespace")>>
25+
<<\Entity("import absolute from global")>>
26+
function foo() {
27+
}
28+
}
29+
30+
namespace {
31+
class Entity {}
32+
33+
dump_attributes((new ReflectionFunction('Foo\foo'))->getAttributes());
34+
}
35+
?>
36+
--EXPECTF--
37+
array(4) {
38+
[0]=>
39+
array(2) {
40+
["name"]=>
41+
string(27) "Doctrine\ORM\Mapping\Entity"
42+
["args"]=>
43+
array(1) {
44+
[0]=>
45+
string(14) "imported class"
46+
}
47+
}
48+
[1]=>
49+
array(2) {
50+
["name"]=>
51+
string(27) "Doctrine\ORM\Mapping\Entity"
52+
["args"]=>
53+
array(1) {
54+
[0]=>
55+
string(18) "imported namespace"
56+
}
57+
}
58+
[2]=>
59+
array(2) {
60+
["name"]=>
61+
string(27) "Doctrine\ORM\Mapping\Entity"
62+
["args"]=>
63+
array(1) {
64+
[0]=>
65+
string(23) "absolute from namespace"
66+
}
67+
}
68+
[3]=>
69+
array(2) {
70+
["name"]=>
71+
string(6) "Entity"
72+
["args"]=>
73+
array(1) {
74+
[0]=>
75+
string(27) "import absolute from global"
76+
}
77+
}
78+
}

0 commit comments

Comments
 (0)