Skip to content

Commit 053ef28

Browse files
kooldevnikic
authored andcommitted
Implement Attribute Amendments.
RFC: https://wiki.php.net/rfc/attribute_amendments Support for attribute grouping is left out, because the short attribute syntax RFC will likely make it obsolete. Closes GH-5751.
1 parent 46e38a1 commit 053ef28

22 files changed

+502
-75
lines changed

UPGRADING

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,7 @@ PHP 8.0 UPGRADE NOTES
554554
RFC: https://wiki.php.net/rfc/mixed_type_v2
555555
. Added support for Attributes
556556
RFC: https://wiki.php.net/rfc/attributes_v2
557+
RFC: https://wiki.php.net/rfc/attribute_amendments
557558
. Added support for constructor property promotion (declaring properties in
558559
the constructor signature).
559560
RFC: https://wiki.php.net/rfc/constructor_promotion

Zend/tests/attributes/002_rfcexample.phpt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ Attributes: Example from Attributes RFC
44
<?php
55
// https://wiki.php.net/rfc/attributes_v2#attribute_syntax
66
namespace My\Attributes {
7-
use PhpAttribute;
7+
use Attribute;
88

9-
<<PhpAttribute>>
9+
<<Attribute>>
1010
class SingleArgument {
1111
public $argumentValue;
1212

@@ -37,7 +37,7 @@ array(1) {
3737
[0]=>
3838
string(11) "Hello World"
3939
}
40-
object(My\Attributes\SingleArgument)#3 (1) {
40+
object(My\Attributes\SingleArgument)#%d (1) {
4141
["argumentValue"]=>
4242
string(11) "Hello World"
4343
}

Zend/tests/attributes/003_ast_nodes.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ var_dump($ref->getAttributes()[0]->getArguments());
5959

6060
echo "\n";
6161

62-
<<PhpAttribute>>
62+
<<Attribute>>
6363
class C5
6464
{
6565
public function __construct() { }

Zend/tests/attributes/005_objects.phpt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Attributes can be converted into objects.
33
--FILE--
44
<?php
55

6-
<<PhpAttribute>>
6+
<<Attribute(Attribute::TARGET_FUNCTION)>>
77
class A1
88
{
99
public string $name;
@@ -56,7 +56,7 @@ try {
5656

5757
echo "\n";
5858

59-
<<PhpAttribute>>
59+
<<Attribute>>
6060
class A3
6161
{
6262
private function __construct() { }
@@ -72,7 +72,7 @@ try {
7272

7373
echo "\n";
7474

75-
<<PhpAttribute>>
75+
<<Attribute>>
7676
class A4 { }
7777

7878
$ref = new \ReflectionFunction(<<A4(1)>> function () { });
@@ -117,4 +117,4 @@ string(7) "ERROR 5"
117117
string(71) "Attribute class 'A4' does not have a constructor, cannot pass arguments"
118118

119119
string(7) "ERROR 6"
120-
string(78) "Attempting to use class 'A5' as attribute that does not have <<PhpAttribute>>."
120+
string(55) "Attempting to use non-attribute class 'A5' as attribute"
Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
11
--TEST--
2-
Attributes: attributes on PhpAttribute return itself
2+
Attributes: attributes on Attribute return itself
33
--FILE--
44
<?php
55

6-
$reflection = new \ReflectionClass(PhpAttribute::class);
6+
$reflection = new \ReflectionClass(Attribute::class);
77
$attributes = $reflection->getAttributes();
88

99
foreach ($attributes as $attribute) {
1010
var_dump($attribute->getName());
1111
var_dump($attribute->getArguments());
12-
var_dump($attribute->newInstance());
12+
13+
$a = $attribute->newInstance();
14+
var_dump(get_class($a));
15+
var_dump($a->flags == Attribute::TARGET_ALL);
1316
}
1417
--EXPECTF--
15-
string(12) "PhpAttribute"
18+
string(9) "Attribute"
1619
array(0) {
1720
}
18-
object(PhpAttribute)#3 (0) {
19-
}
21+
string(9) "Attribute"
22+
bool(true)
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
--TEST--
2-
Attributes: Prevent PhpAttribute on non classes
2+
Attributes: Prevent Attribute on non classes
33
--FILE--
44
<?php
55

6-
<<PhpAttribute>>
6+
<<Attribute>>
77
function foo() {}
88
--EXPECTF--
9-
Fatal error: Only classes can be marked with <<PhpAttribute>> in %s
9+
Fatal error: Attribute "Attribute" cannot target function (allowed targets: class) in %s
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
--TEST--
2+
Attributes expose and verify target and repeatable data.
3+
--FILE--
4+
<?php
5+
6+
<<Attribute(Attribute::TARGET_FUNCTION | Attribute::TARGET_METHOD)>>
7+
class A1 { }
8+
9+
$ref = new \ReflectionFunction(<<A1>> function () { });
10+
$attr = $ref->getAttributes()[0];
11+
var_dump($attr->getName(), $attr->getTarget() == Attribute::TARGET_FUNCTION, $attr->isRepeated());
12+
var_dump(get_class($attr->newInstance()));
13+
14+
echo "\n";
15+
16+
$ref = new \ReflectionObject(new <<A1>> class() { });
17+
$attr = $ref->getAttributes()[0];
18+
var_dump($attr->getName(), $attr->getTarget() == Attribute::TARGET_CLASS, $attr->isRepeated());
19+
20+
try {
21+
$attr->newInstance();
22+
} catch (\Throwable $e) {
23+
var_dump('ERROR 1', $e->getMessage());
24+
}
25+
26+
echo "\n";
27+
28+
$ref = new \ReflectionFunction(<<A1>> <<A1>> function () { });
29+
$attr = $ref->getAttributes()[0];
30+
var_dump($attr->getName(), $attr->getTarget() == Attribute::TARGET_FUNCTION, $attr->isRepeated());
31+
32+
try {
33+
$attr->newInstance();
34+
} catch (\Throwable $e) {
35+
var_dump('ERROR 2', $e->getMessage());
36+
}
37+
38+
echo "\n";
39+
40+
<<Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)>>
41+
class A2 { }
42+
43+
$ref = new \ReflectionObject(new <<A2>> <<A2>> class() { });
44+
$attr = $ref->getAttributes()[0];
45+
var_dump($attr->getName(), $attr->getTarget() == Attribute::TARGET_CLASS, $attr->isRepeated());
46+
var_dump(get_class($attr->newInstance()));
47+
48+
?>
49+
--EXPECT--
50+
string(2) "A1"
51+
bool(true)
52+
bool(false)
53+
string(2) "A1"
54+
55+
string(2) "A1"
56+
bool(true)
57+
bool(false)
58+
string(7) "ERROR 1"
59+
string(70) "Attribute "A1" cannot target class (allowed targets: function, method)"
60+
61+
string(2) "A1"
62+
bool(true)
63+
bool(true)
64+
string(7) "ERROR 2"
65+
string(35) "Attribute "A1" must not be repeated"
66+
67+
string(2) "A2"
68+
bool(true)
69+
bool(true)
70+
string(2) "A2"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
--TEST--
2+
Attribute flags type is validated.
3+
--FILE--
4+
<?php
5+
6+
<<Attribute("foo")>>
7+
class A1 { }
8+
9+
?>
10+
--EXPECTF--
11+
Fatal error: Attribute::__construct(): Argument #1 ($flags) must must be of type int, string given in %s
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
--TEST--
2+
Attribute flags value is validated.
3+
--FILE--
4+
<?php
5+
6+
<<Attribute(-1)>>
7+
class A1 { }
8+
9+
?>
10+
--EXPECTF--
11+
Fatal error: Invalid attribute flags specified in %s
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
--TEST--
2+
Attribute flags value is validated.
3+
--FILE--
4+
<?php
5+
6+
<<Attribute(Foo::BAR)>>
7+
class A1 { }
8+
9+
?>
10+
--EXPECTF--
11+
Fatal error: Class 'Foo' not found in %s
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
--TEST--
2+
Internal attribute targets are validated.
3+
--FILE--
4+
<?php
5+
6+
<<Attribute>>
7+
function a1() { }
8+
9+
?>
10+
--EXPECTF--
11+
Fatal error: Attribute "Attribute" cannot target function (allowed targets: class) in %s
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
Internal attribute targets are validated.
3+
--FILE--
4+
<?php
5+
6+
<<Attribute>>
7+
<<Attribute>>
8+
class A1 { }
9+
10+
?>
11+
--EXPECTF--
12+
Fatal error: Attribute "Attribute" must not be repeated in %s

0 commit comments

Comments
 (0)