summaryrefslogtreecommitdiff
path: root/Zend
diff options
context:
space:
mode:
authorBenjamin Eberlei <kontakt@beberlei.de>2020-08-15 10:39:00 +0200
committerBenjamin Eberlei <kontakt@beberlei.de>2020-09-02 20:26:50 +0200
commit8b37c1e993f17345312a76a239b77ae137d3f8e8 (patch)
tree606fc07aee5d8531712f1bb008a8e5abe052540c /Zend
parentf2b40775af7165d0f343fe6351e0d468403c111b (diff)
downloadphp-git-8b37c1e993f17345312a76a239b77ae137d3f8e8.tar.gz
Change Attribute Syntax from @@ to #[]
Diffstat (limited to 'Zend')
-rw-r--r--Zend/tests/attributes/001_placement.phpt26
-rw-r--r--Zend/tests/attributes/002_rfcexample.phpt4
-rw-r--r--Zend/tests/attributes/003_ast_nodes.phpt12
-rw-r--r--Zend/tests/attributes/004_name_resolution.phpt10
-rw-r--r--Zend/tests/attributes/005_objects.phpt20
-rw-r--r--Zend/tests/attributes/006_filter.phpt16
-rw-r--r--Zend/tests/attributes/008_wrong_attribution.phpt2
-rw-r--r--Zend/tests/attributes/009_doctrine_annotations_example.phpt24
-rw-r--r--Zend/tests/attributes/010_unsupported_const_expression.phpt2
-rw-r--r--Zend/tests/attributes/011_inheritance.phpt10
-rw-r--r--Zend/tests/attributes/012_ast_export.phpt38
-rw-r--r--Zend/tests/attributes/013_class_scope.phpt16
-rw-r--r--Zend/tests/attributes/014_class_const_group.phpt2
-rw-r--r--Zend/tests/attributes/015_property_group.phpt2
-rw-r--r--Zend/tests/attributes/016_custom_attribute_validation.phpt4
-rw-r--r--Zend/tests/attributes/017_closure_scope.phpt2
-rw-r--r--Zend/tests/attributes/018_fatal_error_in_argument.phpt2
-rw-r--r--Zend/tests/attributes/019_variable_attribute_name.phpt2
-rw-r--r--Zend/tests/attributes/020_userland_attribute_validation.phpt12
-rw-r--r--Zend/tests/attributes/021_attribute_flags_type_is_validated.phpt2
-rw-r--r--Zend/tests/attributes/022_attribute_flags_value_is_validated.phpt2
-rw-r--r--Zend/tests/attributes/023_ast_node_in_validation.phpt2
-rw-r--r--Zend/tests/attributes/024_internal_target_validation.phpt2
-rw-r--r--Zend/tests/attributes/025_internal_repeatable_validation.phpt4
-rw-r--r--Zend/tests/attributes/026_unpack_in_args.phpt2
-rw-r--r--Zend/tests/attributes/027_trailing_comma_args.phpt4
-rw-r--r--Zend/tests/attributes/028_grouped.phpt55
-rw-r--r--Zend/tests/bug79897.phpt4
-rw-r--r--Zend/tests/ctor_promotion_attributes.phpt2
-rw-r--r--Zend/tests/named_params/attributes.phpt6
-rw-r--r--Zend/tests/named_params/attributes_duplicate_named_param.phpt2
-rw-r--r--Zend/tests/named_params/attributes_named_flags.phpt4
-rw-r--r--Zend/tests/named_params/attributes_named_flags_incorrect.phpt4
-rw-r--r--Zend/tests/named_params/attributes_positional_after_named.phpt4
-rw-r--r--Zend/tests/varSyntax/globalNonSimpleVariableError.phpt2
-rw-r--r--Zend/zend_ast.c20
-rw-r--r--Zend/zend_ast.h1
-rw-r--r--Zend/zend_compile.c70
-rw-r--r--Zend/zend_language_parser.y13
-rw-r--r--Zend/zend_language_scanner.l3
40 files changed, 248 insertions, 166 deletions
diff --git a/Zend/tests/attributes/001_placement.phpt b/Zend/tests/attributes/001_placement.phpt
index 9bf9c4d2f7..7de2210460 100644
--- a/Zend/tests/attributes/001_placement.phpt
+++ b/Zend/tests/attributes/001_placement.phpt
@@ -3,27 +3,27 @@ Attributes can be placed on all supported elements.
--FILE--
<?php
-@@A1(1)
+#[A1(1)]
class Foo
{
- @@A1(2)
+ #[A1(2)]
public const FOO = 'foo';
-
- @@A1(3)
+
+ #[A1(3)]
public $x;
-
- @@A1(4)
- public function foo(@@A1(5) $a, @@A1(6) $b) { }
+
+ #[A1(4)]
+ public function foo(#[A1(5)] $a, #[A1(6)] $b) { }
}
-$object = new @@A1(7) class () { };
+$object = new #[A1(7)] class () { };
-@@A1(8)
+#[A1(8)]
function f1() { }
-$f2 = @@A1(9) function () { };
+$f2 = #[A1(9)] function () { };
-$f3 = @@A1(10) fn () => 1;
+$f3 = #[A1(10)] fn () => 1;
$ref = new \ReflectionClass(Foo::class);
@@ -43,11 +43,11 @@ $sources = [
foreach ($sources as $r) {
$attr = $r->getAttributes();
var_dump(get_class($r), count($attr));
-
+
foreach ($attr as $a) {
var_dump($a->getName(), $a->getArguments());
}
-
+
echo "\n";
}
diff --git a/Zend/tests/attributes/002_rfcexample.phpt b/Zend/tests/attributes/002_rfcexample.phpt
index bc608c3eed..8a0abf7878 100644
--- a/Zend/tests/attributes/002_rfcexample.phpt
+++ b/Zend/tests/attributes/002_rfcexample.phpt
@@ -6,7 +6,7 @@ Attributes: Example from Attributes RFC
namespace My\Attributes {
use Attribute;
- @@Attribute
+ #[Attribute]
class SingleArgument {
public $argumentValue;
@@ -19,7 +19,7 @@ namespace My\Attributes {
namespace {
use My\Attributes\SingleArgument;
- @@SingleArgument("Hello World")
+ #[SingleArgument("Hello World")]
class Foo {
}
diff --git a/Zend/tests/attributes/003_ast_nodes.phpt b/Zend/tests/attributes/003_ast_nodes.phpt
index 21125bde13..0177804dcc 100644
--- a/Zend/tests/attributes/003_ast_nodes.phpt
+++ b/Zend/tests/attributes/003_ast_nodes.phpt
@@ -5,7 +5,7 @@ Attributes can deal with AST nodes.
define('V1', strtoupper(php_sapi_name()));
-@@A1([V1 => V1])
+#[A1([V1 => V1])]
class C1
{
public const BAR = 'bar';
@@ -20,7 +20,7 @@ var_dump(count($args), $args[0][V1] === V1);
echo "\n";
-@@A1(V1, 1 + 2, C1::class)
+#[A1(V1, 1 + 2, C1::class)]
class C2 { }
$ref = new \ReflectionClass(C2::class);
@@ -35,7 +35,7 @@ var_dump($args[2] === C1::class);
echo "\n";
-@@A1(self::FOO, C1::BAR)
+#[A1(self::FOO, C1::BAR)]
class C3
{
private const FOO = 'foo';
@@ -52,20 +52,20 @@ var_dump($args[1] === C1::BAR);
echo "\n";
-@@ExampleWithShift(4 >> 1)
+#[ExampleWithShift(4 >> 1)]
class C4 {}
$ref = new \ReflectionClass(C4::class);
var_dump($ref->getAttributes()[0]->getArguments());
echo "\n";
-@@Attribute
+#[Attribute]
class C5
{
public function __construct() { }
}
-$ref = new \ReflectionFunction(@@C5(MissingClass::SOME_CONST) function () { });
+$ref = new \ReflectionFunction(#[C5(MissingClass::SOME_CONST)] function () { });
$attr = $ref->getAttributes();
var_dump(count($attr));
diff --git a/Zend/tests/attributes/004_name_resolution.phpt b/Zend/tests/attributes/004_name_resolution.phpt
index 3c0e1190ff..6f266908b5 100644
--- a/Zend/tests/attributes/004_name_resolution.phpt
+++ b/Zend/tests/attributes/004_name_resolution.phpt
@@ -25,11 +25,11 @@ namespace Foo {
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()
+ #[Entity("imported class")]
+ #[ORM\Entity("imported namespace")]
+ #[\Doctrine\ORM\Mapping\Entity("absolute from namespace")]
+ #[\Entity("import absolute from global")]
+ #[Attributes\Table()]
function foo() {
}
}
diff --git a/Zend/tests/attributes/005_objects.phpt b/Zend/tests/attributes/005_objects.phpt
index 83f523182b..206d89fa10 100644
--- a/Zend/tests/attributes/005_objects.phpt
+++ b/Zend/tests/attributes/005_objects.phpt
@@ -3,7 +3,7 @@ Attributes can be converted into objects.
--FILE--
<?php
-@@Attribute(Attribute::TARGET_FUNCTION)
+#[Attribute(Attribute::TARGET_FUNCTION)]
class A1
{
public string $name;
@@ -16,7 +16,7 @@ class A1
}
}
-$ref = new \ReflectionFunction(@@A1('test') function () { });
+$ref = new \ReflectionFunction(#[A1('test')] function () { });
foreach ($ref->getAttributes() as $attr) {
$obj = $attr->newInstance();
@@ -26,7 +26,7 @@ foreach ($ref->getAttributes() as $attr) {
echo "\n";
-$ref = new \ReflectionFunction(@@A1 function () { });
+$ref = new \ReflectionFunction(#[A1] function () { });
try {
$ref->getAttributes()[0]->newInstance();
@@ -36,7 +36,7 @@ try {
echo "\n";
-$ref = new \ReflectionFunction(@@A1([]) function () { });
+$ref = new \ReflectionFunction(#[A1([])] function () { });
try {
$ref->getAttributes()[0]->newInstance();
@@ -46,7 +46,7 @@ try {
echo "\n";
-$ref = new \ReflectionFunction(@@A2 function () { });
+$ref = new \ReflectionFunction(#[A2] function () { });
try {
$ref->getAttributes()[0]->newInstance();
@@ -56,13 +56,13 @@ try {
echo "\n";
-@@Attribute
+#[Attribute]
class A3
{
private function __construct() { }
}
-$ref = new \ReflectionFunction(@@A3 function () { });
+$ref = new \ReflectionFunction(#[A3] function () { });
try {
$ref->getAttributes()[0]->newInstance();
@@ -72,10 +72,10 @@ try {
echo "\n";
-@@Attribute
+#[Attribute]
class A4 { }
-$ref = new \ReflectionFunction(@@A4(1) function () { });
+$ref = new \ReflectionFunction(#[A4(1)] function () { });
try {
$ref->getAttributes()[0]->newInstance();
@@ -87,7 +87,7 @@ echo "\n";
class A5 { }
-$ref = new \ReflectionFunction(@@A5 function () { });
+$ref = new \ReflectionFunction(#[A5] function () { });
try {
$ref->getAttributes()[0]->newInstance();
diff --git a/Zend/tests/attributes/006_filter.phpt b/Zend/tests/attributes/006_filter.phpt
index 69ee146b49..8da1ec9bde 100644
--- a/Zend/tests/attributes/006_filter.phpt
+++ b/Zend/tests/attributes/006_filter.phpt
@@ -3,17 +3,17 @@ Attributes can be filtered by name and base type.
--FILE--
<?php
-$ref = new \ReflectionFunction(@@A1 @@A2 function () { });
+$ref = new \ReflectionFunction(#[A1] #[A2] function () { });
$attr = $ref->getAttributes(A3::class);
var_dump(count($attr));
-$ref = new \ReflectionFunction(@@A1 @@A2 function () { });
+$ref = new \ReflectionFunction(#[A1] #[A2] function () { });
$attr = $ref->getAttributes(A2::class);
var_dump(count($attr), $attr[0]->getName());
-$ref = new \ReflectionFunction(@@A1 @@A2 @@A2 function () { });
+$ref = new \ReflectionFunction(#[A1] #[A2] #[A2] function () { });
$attr = $ref->getAttributes(A2::class);
var_dump(count($attr), $attr[0]->getName(), $attr[1]->getName());
@@ -25,27 +25,27 @@ class A1 implements Base { }
class A2 implements Base { }
class A3 extends A2 { }
-$ref = new \ReflectionFunction(@@A1 @@A2 @@A5 function () { });
+$ref = new \ReflectionFunction(#[A1] #[A2] #[A5] function () { });
$attr = $ref->getAttributes(\stdClass::class, \ReflectionAttribute::IS_INSTANCEOF);
var_dump(count($attr));
print_r(array_map(fn ($a) => $a->getName(), $attr));
-$ref = new \ReflectionFunction(@@A1 @@A2 function () { });
+$ref = new \ReflectionFunction(#[A1] #[A2] function () { });
$attr = $ref->getAttributes(A1::class, \ReflectionAttribute::IS_INSTANCEOF);
var_dump(count($attr));
print_r(array_map(fn ($a) => $a->getName(), $attr));
-$ref = new \ReflectionFunction(@@A1 @@A2 function () { });
+$ref = new \ReflectionFunction(#[A1] #[A2] function () { });
$attr = $ref->getAttributes(Base::class, \ReflectionAttribute::IS_INSTANCEOF);
var_dump(count($attr));
print_r(array_map(fn ($a) => $a->getName(), $attr));
-$ref = new \ReflectionFunction(@@A1 @@A2 @@A3 function () { });
+$ref = new \ReflectionFunction(#[A1] #[A2] #[A3] function () { });
$attr = $ref->getAttributes(A2::class, \ReflectionAttribute::IS_INSTANCEOF);
var_dump(count($attr));
print_r(array_map(fn ($a) => $a->getName(), $attr));
-$ref = new \ReflectionFunction(@@A1 @@A2 @@A3 function () { });
+$ref = new \ReflectionFunction(#[A1] #[A2] #[A3] function () { });
$attr = $ref->getAttributes(Base::class, \ReflectionAttribute::IS_INSTANCEOF);
var_dump(count($attr));
print_r(array_map(fn ($a) => $a->getName(), $attr));
diff --git a/Zend/tests/attributes/008_wrong_attribution.phpt b/Zend/tests/attributes/008_wrong_attribution.phpt
index 5a3ec54a6f..af61bcf105 100644
--- a/Zend/tests/attributes/008_wrong_attribution.phpt
+++ b/Zend/tests/attributes/008_wrong_attribution.phpt
@@ -3,7 +3,7 @@ Attributes: Prevent Attribute on non classes
--FILE--
<?php
-@@Attribute
+#[Attribute]
function foo() {}
?>
--EXPECTF--
diff --git a/Zend/tests/attributes/009_doctrine_annotations_example.phpt b/Zend/tests/attributes/009_doctrine_annotations_example.phpt
index 51cb315d48..1f2aa647f0 100644
--- a/Zend/tests/attributes/009_doctrine_annotations_example.phpt
+++ b/Zend/tests/attributes/009_doctrine_annotations_example.phpt
@@ -25,22 +25,22 @@ namespace {
use Doctrine\ORM\Attributes as ORM;
use Symfony\Component\Validator\Constraints as Assert;
-@@ORM\Entity
+#[ORM\Entity]
/** @ORM\Entity */
class User
{
/** @ORM\Id @ORM\Column(type="integer"*) @ORM\GeneratedValue */
- @@ORM\Id
- @@ORM\Column("integer")
- @@ORM\GeneratedValue
+ #[ORM\Id]
+ #[ORM\Column("integer")]
+ #[ORM\GeneratedValue]
private $id;
/**
* @ORM\Column(type="string", unique=true)
* @Assert\Email(message="The email '{{ value }}' is not a valid email.")
*/
- @@ORM\Column("string", ORM\Column::UNIQUE)
- @@Assert\Email(array("message" => "The email '{{ value }}' is not a valid email."))
+ #[ORM\Column("string", ORM\Column::UNIQUE)]
+ #[Assert\Email(array("message" => "The email '{{ value }}' is not a valid email."))]
private $email;
/**
@@ -52,8 +52,8 @@ class User
* maxMessage = "You cannot be taller than {{ limit }}cm to enter"
* )
*/
- @@Assert\Range(["min" => 120, "max" => 180, "minMessage" => "You must be at least {{ limit }}cm tall to enter"])
- @@ORM\Column(ORM\Column::T_INTEGER)
+ #[Assert\Range(["min" => 120, "max" => 180, "minMessage" => "You must be at least {{ limit }}cm tall to enter"])]
+ #[ORM\Column(ORM\Column::T_INTEGER)]
protected $height;
/**
@@ -63,10 +63,10 @@ class User
* inverseJoinColumns={@ORM\JoinColumn(name="phonenumber_id", referencedColumnName="id", unique=true)}
* )
*/
- @@ORM\ManyToMany(Phonenumber::class)
- @@ORM\JoinTable("users_phonenumbers")
- @@ORM\JoinColumn("user_id", "id")
- @@ORM\InverseJoinColumn("phonenumber_id", "id", ORM\JoinColumn::UNIQUE)
+ #[ORM\ManyToMany(Phonenumber::class)]
+ #[ORM\JoinTable("users_phonenumbers")]
+ #[ORM\JoinColumn("user_id", "id")]
+ #[ORM\InverseJoinColumn("phonenumber_id", "id", ORM\JoinColumn::UNIQUE)]
private $phonenumbers;
}
diff --git a/Zend/tests/attributes/010_unsupported_const_expression.phpt b/Zend/tests/attributes/010_unsupported_const_expression.phpt
index fb30e2c486..498898379d 100644
--- a/Zend/tests/attributes/010_unsupported_const_expression.phpt
+++ b/Zend/tests/attributes/010_unsupported_const_expression.phpt
@@ -3,7 +3,7 @@ Attribute arguments support only const expressions.
--FILE--
<?php
-@@A1(foo())
+#[A1(foo())]
class C1 { }
?>
diff --git a/Zend/tests/attributes/011_inheritance.phpt b/Zend/tests/attributes/011_inheritance.phpt
index 25c943dea3..36ee3fa47a 100644
--- a/Zend/tests/attributes/011_inheritance.phpt
+++ b/Zend/tests/attributes/011_inheritance.phpt
@@ -3,10 +3,10 @@ Attributes comply with inheritance rules.
--FILE--
<?php
-@@A2
+#[A2]
class C1
{
- @@A1
+ #[A1]
public function foo() { }
}
@@ -17,7 +17,7 @@ class C2 extends C1
class C3 extends C1
{
- @@A1
+ #[A1]
public function bar() { }
}
@@ -37,7 +37,7 @@ echo "\n";
trait T1
{
- @@A2
+ #[A2]
public $a;
}
@@ -49,7 +49,7 @@ class C4
class C5
{
use T1;
-
+
public $a;
}
diff --git a/Zend/tests/attributes/012_ast_export.phpt b/Zend/tests/attributes/012_ast_export.phpt
index 9412acc605..a9131f92d0 100644
--- a/Zend/tests/attributes/012_ast_export.phpt
+++ b/Zend/tests/attributes/012_ast_export.phpt
@@ -7,51 +7,51 @@ assert.warning=1
--FILE--
<?php
-assert(0 && ($a = @@A1 @@A2 function ($a, @@A3(1) $b) { }));
+assert(0 && ($a = #[A1] #[A2] function ($a, #[A3(1)] $b) { }));
-assert(0 && ($a = @@A1(1, 2, 1 + 2) fn () => 1));
+assert(0 && ($a = #[A1(1, 2, 1 + 2)] fn () => 1));
-assert(0 && ($a = new @@A1 class() {
- @@A1@@A2 const FOO = 'foo';
- @@A2 public $x;
- @@A3 function a() { }
+assert(0 && ($a = new #[A1] class() {
+ #[A1]#[A2] const FOO = 'foo';
+ #[A2] public $x;
+ #[A3] function a() { }
}));
assert(0 && ($a = function () {
- @@A1 class Test1 { }
- @@A2 interface Test2 { }
- @@A3 trait Test3 { }
+ #[A1] class Test1 { }
+ #[A2] interface Test2 { }
+ #[A3] trait Test3 { }
}));
?>
--EXPECTF--
-Warning: assert(): assert(0 && ($a = @@A1 @@A2 function ($a, @@A3(1) $b) {
+Warning: assert(): assert(0 && ($a = #[A1] #[A2] function ($a, #[A3(1)] $b) {
})) failed in %s on line %d
-Warning: assert(): assert(0 && ($a = @@A1(1, 2, 1 + 2) fn() => 1)) failed in %s on line %d
+Warning: assert(): assert(0 && ($a = #[A1(1, 2, 1 + 2)] fn() => 1)) failed in %s on line %d
-Warning: assert(): assert(0 && ($a = new @@A1 class {
- @@A1
- @@A2
+Warning: assert(): assert(0 && ($a = new #[A1] class {
+ #[A1]
+ #[A2]
public const FOO = 'foo';
- @@A2
+ #[A2]
public $x;
- @@A3
+ #[A3]
public function a() {
}
})) failed in %s on line %d
Warning: assert(): assert(0 && ($a = function () {
- @@A1
+ #[A1]
class Test1 {
}
- @@A2
+ #[A2]
interface Test2 {
}
- @@A3
+ #[A3]
trait Test3 {
}
diff --git a/Zend/tests/attributes/013_class_scope.phpt b/Zend/tests/attributes/013_class_scope.phpt
index be6c7a60da..61dd9f594c 100644
--- a/Zend/tests/attributes/013_class_scope.phpt
+++ b/Zend/tests/attributes/013_class_scope.phpt
@@ -3,17 +3,17 @@ Attributes make use of class scope.
--FILE--
<?php
-@@A1(self::class, self::FOO)
+#[A1(self::class, self::FOO)]
class C1
{
- @@A1(self::class, self::FOO)
+ #[A1(self::class, self::FOO)]
private const FOO = 'foo';
- @@A1(self::class, self::FOO)
+ #[A1(self::class, self::FOO)]
public $a;
- @@A1(self::class, self::FOO)
- public function bar(@@A1(self::class, self::FOO) $p) { }
+ #[A1(self::class, self::FOO)]
+ public function bar(#[A1(self::class, self::FOO)] $p) { }
}
$ref = new \ReflectionClass(C1::class);
@@ -27,7 +27,7 @@ echo "\n";
trait T1
{
- @@A1(self::class, self::FOO)
+ #[A1(self::class, self::FOO)]
public function foo() { }
}
@@ -58,10 +58,10 @@ class C3
public static function foo()
{
- return new @@A1(self::class, self::FOO) class() {
+ return new #[A1(self::class, self::FOO)] class() {
private const FOO = 'bar';
- @@A1(self::class, self::FOO)
+ #[A1(self::class, self::FOO)]
public function bar() { }
};
}
diff --git a/Zend/tests/attributes/014_class_const_group.phpt b/Zend/tests/attributes/014_class_const_group.phpt
index 5da5c52a95..a53ed09c0a 100644
--- a/Zend/tests/attributes/014_class_const_group.phpt
+++ b/Zend/tests/attributes/014_class_const_group.phpt
@@ -5,7 +5,7 @@ Attributes cannot be applied to groups of class constants.
class C1
{
- @@A1
+ #[A1]
public const A = 1, B = 2;
}
diff --git a/Zend/tests/attributes/015_property_group.phpt b/Zend/tests/attributes/015_property_group.phpt
index 52e3b0a92a..484d4154cf 100644
--- a/Zend/tests/attributes/015_property_group.phpt
+++ b/Zend/tests/attributes/015_property_group.phpt
@@ -5,7 +5,7 @@ Attributes cannot be applied to groups of properties.
class C1
{
- @@A1
+ #[A1]
public $x, $y;
}
diff --git a/Zend/tests/attributes/016_custom_attribute_validation.phpt b/Zend/tests/attributes/016_custom_attribute_validation.phpt
index 9971085274..0f3167f986 100644
--- a/Zend/tests/attributes/016_custom_attribute_validation.phpt
+++ b/Zend/tests/attributes/016_custom_attribute_validation.phpt
@@ -8,9 +8,9 @@ if (!extension_loaded('zend-test')) {
--FILE--
<?php
-@@ZendTestAttribute
+#[ZendTestAttribute]
function foo() {
}
?>
--EXPECTF--
-Fatal error: Only classes can be marked with @@ZendTestAttribute in %s
+Fatal error: Only classes can be marked with #[ZendTestAttribute] in %s
diff --git a/Zend/tests/attributes/017_closure_scope.phpt b/Zend/tests/attributes/017_closure_scope.phpt
index 936a8ec338..af7de8e2e8 100644
--- a/Zend/tests/attributes/017_closure_scope.phpt
+++ b/Zend/tests/attributes/017_closure_scope.phpt
@@ -14,7 +14,7 @@ class C1
public static function foo()
{
- return @@A1(self::class, self::FOO) function (@@A1(self::class, self::FOO) $p) { };
+ return #[A1(self::class, self::FOO)] function (#[A1(self::class, self::FOO)] $p) { };
}
}
diff --git a/Zend/tests/attributes/018_fatal_error_in_argument.phpt b/Zend/tests/attributes/018_fatal_error_in_argument.phpt
index db2719d85a..fd031f5c2c 100644
--- a/Zend/tests/attributes/018_fatal_error_in_argument.phpt
+++ b/Zend/tests/attributes/018_fatal_error_in_argument.phpt
@@ -3,7 +3,7 @@ Don't free uninitialized memory if a fatal error occurs in an attribute argument
--FILE--
<?php
-@@Attr(a->b::c)
+#[Attr(a->b::c)]
function test() {}
?>
diff --git a/Zend/tests/attributes/019_variable_attribute_name.phpt b/Zend/tests/attributes/019_variable_attribute_name.phpt
index 9b8a3c2211..fe96459bb3 100644
--- a/Zend/tests/attributes/019_variable_attribute_name.phpt
+++ b/Zend/tests/attributes/019_variable_attribute_name.phpt
@@ -3,7 +3,7 @@ Attribute name cannot be a variable
--FILE--
<?php
-@@$x
+#[$x]
class A {}
?>
diff --git a/Zend/tests/attributes/020_userland_attribute_validation.phpt b/Zend/tests/attributes/020_userland_attribute_validation.phpt
index 1025b5008e..14a10c39b2 100644
--- a/Zend/tests/attributes/020_userland_attribute_validation.phpt
+++ b/Zend/tests/attributes/020_userland_attribute_validation.phpt
@@ -3,17 +3,17 @@ Attributes expose and verify target and repeatable data.
--FILE--
<?php
-@@Attribute(Attribute::TARGET_FUNCTION | Attribute::TARGET_METHOD)
+#[Attribute(Attribute::TARGET_FUNCTION | Attribute::TARGET_METHOD)]
class A1 { }
-$ref = new \ReflectionFunction(@@A1 function () { });
+$ref = new \ReflectionFunction(#[A1] function () { });
$attr = $ref->getAttributes()[0];
var_dump($attr->getName(), $attr->getTarget() == Attribute::TARGET_FUNCTION, $attr->isRepeated());
var_dump(get_class($attr->newInstance()));
echo "\n";
-$ref = new \ReflectionObject(new @@A1 class() { });
+$ref = new \ReflectionObject(new #[A1] class() { });
$attr = $ref->getAttributes()[0];
var_dump($attr->getName(), $attr->getTarget() == Attribute::TARGET_CLASS, $attr->isRepeated());
@@ -25,7 +25,7 @@ try {
echo "\n";
-$ref = new \ReflectionFunction(@@A1 @@A1 function () { });
+$ref = new \ReflectionFunction(#[A1] #[A1] function () { });
$attr = $ref->getAttributes()[0];
var_dump($attr->getName(), $attr->getTarget() == Attribute::TARGET_FUNCTION, $attr->isRepeated());
@@ -37,10 +37,10 @@ try {
echo "\n";
-@@Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)
+#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
class A2 { }
-$ref = new \ReflectionObject(new @@A2 @@A2 class() { });
+$ref = new \ReflectionObject(new #[A2] #[A2] class() { });
$attr = $ref->getAttributes()[0];
var_dump($attr->getName(), $attr->getTarget() == Attribute::TARGET_CLASS, $attr->isRepeated());
var_dump(get_class($attr->newInstance()));
diff --git a/Zend/tests/attributes/021_attribute_flags_type_is_validated.phpt b/Zend/tests/attributes/021_attribute_flags_type_is_validated.phpt
index 0f0b915ebe..7c1bfd2da7 100644
--- a/Zend/tests/attributes/021_attribute_flags_type_is_validated.phpt
+++ b/Zend/tests/attributes/021_attribute_flags_type_is_validated.phpt
@@ -3,7 +3,7 @@ Attribute flags type is validated.
--FILE--
<?php
-@@Attribute("foo")
+#[Attribute("foo")]
class A1 { }
?>
diff --git a/Zend/tests/attributes/022_attribute_flags_value_is_validated.phpt b/Zend/tests/attributes/022_attribute_flags_value_is_validated.phpt
index 28ad550385..72433a9f13 100644
--- a/Zend/tests/attributes/022_attribute_flags_value_is_validated.phpt
+++ b/Zend/tests/attributes/022_attribute_flags_value_is_validated.phpt
@@ -3,7 +3,7 @@ Attribute flags value is validated.
--FILE--
<?php
-@@Attribute(-1)
+#[Attribute(-1)]
class A1 { }
?>
diff --git a/Zend/tests/attributes/023_ast_node_in_validation.phpt b/Zend/tests/attributes/023_ast_node_in_validation.phpt
index ce44527f62..332d83fe86 100644
--- a/Zend/tests/attributes/023_ast_node_in_validation.phpt
+++ b/Zend/tests/attributes/023_ast_node_in_validation.phpt
@@ -3,7 +3,7 @@ Attribute flags value is validated.
--FILE--
<?php
-@@Attribute(Foo::BAR)
+#[Attribute(Foo::BAR)]
class A1 { }
?>
diff --git a/Zend/tests/attributes/024_internal_target_validation.phpt b/Zend/tests/attributes/024_internal_target_validation.phpt
index 49a5ae68c8..e941cf6132 100644
--- a/Zend/tests/attributes/024_internal_target_validation.phpt
+++ b/Zend/tests/attributes/024_internal_target_validation.phpt
@@ -3,7 +3,7 @@ Internal attribute targets are validated.
--FILE--
<?php
-@@Attribute
+#[Attribute]
function a1() { }
?>
diff --git a/Zend/tests/attributes/025_internal_repeatable_validation.phpt b/Zend/tests/attributes/025_internal_repeatable_validation.phpt
index b3c83e810f..671a15fba3 100644
--- a/Zend/tests/attributes/025_internal_repeatable_validation.phpt
+++ b/Zend/tests/attributes/025_internal_repeatable_validation.phpt
@@ -3,8 +3,8 @@ Internal attribute targets are validated.
--FILE--
<?php
-@@Attribute
-@@Attribute
+#[Attribute]
+#[Attribute]
class A1 { }
?>
diff --git a/Zend/tests/attributes/026_unpack_in_args.phpt b/Zend/tests/attributes/026_unpack_in_args.phpt
index 37f8fb5679..d7528b5114 100644
--- a/Zend/tests/attributes/026_unpack_in_args.phpt
+++ b/Zend/tests/attributes/026_unpack_in_args.phpt
@@ -3,7 +3,7 @@ Cannot use unpacking in attribute argument list
--FILE--
<?php
-@@MyAttribute(...[1, 2, 3])
+#[MyAttribute(...[1, 2, 3])]
class Foo { }
?>
diff --git a/Zend/tests/attributes/027_trailing_comma_args.phpt b/Zend/tests/attributes/027_trailing_comma_args.phpt
index 5ac47e08a8..226025f359 100644
--- a/Zend/tests/attributes/027_trailing_comma_args.phpt
+++ b/Zend/tests/attributes/027_trailing_comma_args.phpt
@@ -3,12 +3,12 @@ Trailing comma in attribute argument list
--FILE--
<?php
-@@MyAttribute(
+#[MyAttribute(
"there",
"are",
"many",
"arguments",
-)
+)]
class Foo { }
$ref = new \ReflectionClass(Foo::class);
diff --git a/Zend/tests/attributes/028_grouped.phpt b/Zend/tests/attributes/028_grouped.phpt
new file mode 100644
index 0000000000..9796531bda
--- /dev/null
+++ b/Zend/tests/attributes/028_grouped.phpt
@@ -0,0 +1,55 @@
+--TEST--
+Attributes can be grouped
+--FILE--
+<?php
+
+#[A1(1), A1(2), A2(3)]
+class Foo
+{
+}
+
+#[
+ A1(1),
+ A1(2),
+ A2(3)
+]
+function foo() {}
+
+#[A1, A1, A2]
+function bar() {}
+
+$sources = [
+ new \ReflectionClass(Foo::class),
+ new \ReflectionFunction('foo'),
+ new \ReflectionFunction('bar'),
+];
+
+foreach ($sources as $ref) {
+ $attr = $ref->getAttributes();
+ var_dump(get_class($ref), count($attr));
+
+ foreach ($attr as $a) {
+ printf("%s(%s)\n", $a->getName(), implode(", ", $a->getArguments()));
+ }
+
+ echo "\n";
+}
+?>
+--EXPECT--
+string(15) "ReflectionClass"
+int(3)
+A1(1)
+A1(2)
+A2(3)
+
+string(18) "ReflectionFunction"
+int(3)
+A1(1)
+A1(2)
+A2(3)
+
+string(18) "ReflectionFunction"
+int(3)
+A1()
+A1()
+A2()
diff --git a/Zend/tests/bug79897.phpt b/Zend/tests/bug79897.phpt
index ed79318c76..19869538a4 100644
--- a/Zend/tests/bug79897.phpt
+++ b/Zend/tests/bug79897.phpt
@@ -3,7 +3,7 @@ bug79897: Promoted constructor params with attribs cause crash
--FILE--
<?php
-@@Attribute
+#[Attribute]
class B {
public function __construct($value)
{
@@ -12,7 +12,7 @@ class B {
class A {
public function __construct(
- @@B(12) public $b
+ #[B(12)] public $b
)
{
}
diff --git a/Zend/tests/ctor_promotion_attributes.phpt b/Zend/tests/ctor_promotion_attributes.phpt
index 08c7117daf..1b02eef9df 100644
--- a/Zend/tests/ctor_promotion_attributes.phpt
+++ b/Zend/tests/ctor_promotion_attributes.phpt
@@ -5,7 +5,7 @@ Attributes on promoted properties are assigned to both the property and paramete
class Test {
public function __construct(
- @@NonNegative
+ #[NonNegative]
public int $num,
) {}
}
diff --git a/Zend/tests/named_params/attributes.phpt b/Zend/tests/named_params/attributes.phpt
index 931dbfbe9f..94d2fad19f 100644
--- a/Zend/tests/named_params/attributes.phpt
+++ b/Zend/tests/named_params/attributes.phpt
@@ -3,7 +3,7 @@ Named params in attributes
--FILE--
<?php
-@@Attribute
+#[Attribute]
class MyAttribute {
public function __construct(
public $a = 'a',
@@ -12,10 +12,10 @@ class MyAttribute {
) {}
}
-@@MyAttribute('A', c: 'C')
+#[MyAttribute('A', c: 'C')]
class Test1 {}
-@@MyAttribute('A', a: 'C')
+#[MyAttribute('A', a: 'C')]
class Test2 {}
$attr = (new ReflectionClass(Test1::class))->getAttributes()[0];
diff --git a/Zend/tests/named_params/attributes_duplicate_named_param.phpt b/Zend/tests/named_params/attributes_duplicate_named_param.phpt
index bcd9f9b717..3c4203a6c7 100644
--- a/Zend/tests/named_params/attributes_duplicate_named_param.phpt
+++ b/Zend/tests/named_params/attributes_duplicate_named_param.phpt
@@ -3,7 +3,7 @@ Named params in attributes: Duplicate named parameter error
--FILE--
<?php
-@@MyAttribute(a: 'A', a: 'A')
+#[MyAttribute(a: 'A', a: 'A')]
class Test {}
?>
diff --git a/Zend/tests/named_params/attributes_named_flags.phpt b/Zend/tests/named_params/attributes_named_flags.phpt
index f553aa5308..fcb08755e3 100644
--- a/Zend/tests/named_params/attributes_named_flags.phpt
+++ b/Zend/tests/named_params/attributes_named_flags.phpt
@@ -3,11 +3,11 @@ Named flags parameter for Attribute attribute
--FILE--
<?php
-@@Attribute(flags: Attribute::TARGET_CLASS)
+#[Attribute(flags: Attribute::TARGET_CLASS)]
class MyAttribute {
}
-@@MyAttribute
+#[MyAttribute]
function test() {}
(new ReflectionFunction('test'))->getAttributes()[0]->newInstance();
diff --git a/Zend/tests/named_params/attributes_named_flags_incorrect.phpt b/Zend/tests/named_params/attributes_named_flags_incorrect.phpt
index 6f5b226157..2ad231602f 100644
--- a/Zend/tests/named_params/attributes_named_flags_incorrect.phpt
+++ b/Zend/tests/named_params/attributes_named_flags_incorrect.phpt
@@ -4,11 +4,11 @@ Named flags parameter for Attribute attribute (incorrect parameter name)
<?php
// TODO: This should error at compile-time.
-@@Attribute(not_flags: Attribute::TARGET_CLASS)
+#[Attribute(not_flags: Attribute::TARGET_CLASS)]
class MyAttribute {
}
-@@MyAttribute
+#[MyAttribute]
function test() {}
(new ReflectionFunction('test'))->getAttributes()[0]->newInstance();
diff --git a/Zend/tests/named_params/attributes_positional_after_named.phpt b/Zend/tests/named_params/attributes_positional_after_named.phpt
index 61cee4dc1f..2301635b68 100644
--- a/Zend/tests/named_params/attributes_positional_after_named.phpt
+++ b/Zend/tests/named_params/attributes_positional_after_named.phpt
@@ -3,10 +3,10 @@ Named params in attributes: Positional after named error
--FILE--
<?php
-@@Attribute
+#[Attribute]
class MyAttribute { }
-@@MyAttribute(a: 'A', 'B')
+#[MyAttribute(a: 'A', 'B')]
class Test {}
?>
diff --git a/Zend/tests/varSyntax/globalNonSimpleVariableError.phpt b/Zend/tests/varSyntax/globalNonSimpleVariableError.phpt
index 6162cbc993..f41840cbb3 100644
--- a/Zend/tests/varSyntax/globalNonSimpleVariableError.phpt
+++ b/Zend/tests/varSyntax/globalNonSimpleVariableError.phpt
@@ -7,4 +7,4 @@ global $$foo->bar;
?>
--EXPECTF--
-Parse error: syntax error, unexpected token "->", expecting ";" or "," in %s on line %d
+Parse error: syntax error, unexpected token "->", expecting "," or ";" in %s on line %d
diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c
index f746b408a1..7932bf5974 100644
--- a/Zend/zend_ast.c
+++ b/Zend/zend_ast.c
@@ -1349,19 +1349,20 @@ static ZEND_COLD void zend_ast_export_class_no_header(smart_str *str, zend_ast_d
smart_str_appends(str, "}");
}
-static ZEND_COLD void zend_ast_export_attributes(smart_str *str, zend_ast *ast, int indent, zend_bool newlines) {
+static ZEND_COLD void zend_ast_export_attribute_group(smart_str *str, zend_ast *ast, int indent) {
zend_ast_list *list = zend_ast_get_list(ast);
- uint32_t i;
+ uint32_t i, j;
for (i = 0; i < list->children; i++) {
zend_ast *attr = list->child[i];
- smart_str_appends(str, "@@");
+ if (i) {
+ smart_str_appends(str, ", ");
+ }
zend_ast_export_ns_name(str, attr->child[0], 0, indent);
if (attr->child[1]) {
zend_ast_list *args = zend_ast_get_list(attr->child[1]);
- uint32_t j;
smart_str_appendc(str, '(');
for (j = 0; j < args->children; j++) {
@@ -1372,6 +1373,17 @@ static ZEND_COLD void zend_ast_export_attributes(smart_str *str, zend_ast *ast,
}
smart_str_appendc(str, ')');
}
+ }
+}
+
+static ZEND_COLD void zend_ast_export_attributes(smart_str *str, zend_ast *ast, int indent, zend_bool newlines) {
+ zend_ast_list *list = zend_ast_get_list(ast);
+ uint32_t i;
+
+ for (i = 0; i < list->children; i++) {
+ smart_str_appends(str, "#[");
+ zend_ast_export_attribute_group(str, list->child[i], indent);
+ smart_str_appends(str, "]");
if (newlines) {
smart_str_appendc(str, '\n');
diff --git a/Zend/zend_ast.h b/Zend/zend_ast.h
index 2d72759c39..eb02e9bea0 100644
--- a/Zend/zend_ast.h
+++ b/Zend/zend_ast.h
@@ -63,6 +63,7 @@ enum _zend_ast_kind {
ZEND_AST_USE,
ZEND_AST_TYPE_UNION,
ZEND_AST_ATTRIBUTE_LIST,
+ ZEND_AST_ATTRIBUTE_GROUP,
ZEND_AST_MATCH_ARM_LIST,
/* 0 child nodes */
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index 8d76148fc2..c403a1f54e 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -6214,51 +6214,57 @@ static void zend_compile_attributes(HashTable **attributes, zend_ast *ast, uint3
zend_internal_attribute *config;
zend_ast_list *list = zend_ast_get_list(ast);
- uint32_t i, j;
+ uint32_t g, i, j;
ZEND_ASSERT(ast->kind == ZEND_AST_ATTRIBUTE_LIST);
- for (i = 0; i < list->children; i++) {
- ZEND_ASSERT(list->child[i]->kind == ZEND_AST_ATTRIBUTE);
+ for (g = 0; g < list->children; g++) {
+ zend_ast_list *group = zend_ast_get_list(list->child[g]);
- zend_ast *el = list->child[i];
- zend_string *name = zend_resolve_class_name_ast(el->child[0]);
- zend_ast_list *args = el->child[1] ? zend_ast_get_list(el->child[1]) : NULL;
+ ZEND_ASSERT(group->kind == ZEND_AST_ATTRIBUTE_GROUP);
- attr = zend_add_attribute(attributes, 0, offset, name, args ? args->children : 0);
- zend_string_release(name);
+ for (i = 0; i < group->children; i++) {
+ ZEND_ASSERT(group->child[i]->kind == ZEND_AST_ATTRIBUTE);
- /* Populate arguments */
- if (args) {
- ZEND_ASSERT(args->kind == ZEND_AST_ARG_LIST);
+ zend_ast *el = group->child[i];
+ zend_string *name = zend_resolve_class_name_ast(el->child[0]);
+ zend_ast_list *args = el->child[1] ? zend_ast_get_list(el->child[1]) : NULL;
- zend_bool uses_named_args = 0;
- for (j = 0; j < args->children; j++) {
- zend_ast *arg_ast = args->child[j];
+ attr = zend_add_attribute(attributes, 0, offset, name, args ? args->children : 0);
+ zend_string_release(name);
- if (arg_ast->kind == ZEND_AST_UNPACK) {
- zend_error_noreturn(E_COMPILE_ERROR,
- "Cannot use unpacking in attribute argument list");
- }
+ /* Populate arguments */
+ if (args) {
+ ZEND_ASSERT(args->kind == ZEND_AST_ARG_LIST);
- if (arg_ast->kind == ZEND_AST_NAMED_ARG) {
- attr->args[j].name = zend_string_copy(zend_ast_get_str(arg_ast->child[0]));
- arg_ast = arg_ast->child[1];
- uses_named_args = 1;
+ zend_bool uses_named_args = 0;
+ for (j = 0; j < args->children; j++) {
+ zend_ast *arg_ast = args->child[j];
- for (uint32_t k = 0; k < j; k++) {
- if (attr->args[k].name &&
- zend_string_equals(attr->args[k].name, attr->args[j].name)) {
- zend_error_noreturn(E_COMPILE_ERROR, "Duplicate named parameter $%s",
- ZSTR_VAL(attr->args[j].name));
+ if (arg_ast->kind == ZEND_AST_UNPACK) {
+ zend_error_noreturn(E_COMPILE_ERROR,
+ "Cannot use unpacking in attribute argument list");
+ }
+
+ if (arg_ast->kind == ZEND_AST_NAMED_ARG) {
+ attr->args[j].name = zend_string_copy(zend_ast_get_str(arg_ast->child[0]));
+ arg_ast = arg_ast->child[1];
+ uses_named_args = 1;
+
+ for (uint32_t k = 0; k < j; k++) {
+ if (attr->args[k].name &&
+ zend_string_equals(attr->args[k].name, attr->args[j].name)) {
+ zend_error_noreturn(E_COMPILE_ERROR, "Duplicate named parameter $%s",
+ ZSTR_VAL(attr->args[j].name));
+ }
}
+ } else if (uses_named_args) {
+ zend_error_noreturn(E_COMPILE_ERROR,
+ "Cannot use positional argument after named argument");
}
- } else if (uses_named_args) {
- zend_error_noreturn(E_COMPILE_ERROR,
- "Cannot use positional argument after named argument");
- }
- zend_const_expr_to_zval(&attr->args[j].value, arg_ast);
+ zend_const_expr_to_zval(&attr->args[j].value, arg_ast);
+ }
}
}
}
diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y
index 1a566e352d..ed800c46f8 100644
--- a/Zend/zend_language_parser.y
+++ b/Zend/zend_language_parser.y
@@ -178,7 +178,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
%token <ident> T_NS_C "'__NAMESPACE__'"
%token END 0 "end of file"
-%token T_ATTRIBUTE "'@@'"
+%token T_ATTRIBUTE "'#['"
%token T_PLUS_EQUAL "'+='"
%token T_MINUS_EQUAL "'-='"
%token T_MUL_EQUAL "'*='"
@@ -266,7 +266,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
%type <ast> identifier type_expr_without_static union_type_without_static
%type <ast> inline_function union_type
%type <ast> attributed_statement attributed_class_statement attributed_parameter
-%type <ast> attribute_decl attribute attributes namespace_declaration_name
+%type <ast> attribute_decl attribute attributes attribute_group namespace_declaration_name
%type <ast> match match_arm_list non_empty_match_arm_list match_arm match_arm_cond_list
%type <num> returns_ref function fn is_reference is_variadic variable_modifiers
@@ -345,8 +345,15 @@ attribute_decl:
{ $$ = zend_ast_create(ZEND_AST_ATTRIBUTE, $1, $2); }
;
+attribute_group:
+ attribute_decl
+ { $$ = zend_ast_create_list(1, ZEND_AST_ATTRIBUTE_GROUP, $1); }
+ | attribute_group ',' attribute_decl
+ { $$ = zend_ast_list_add($1, $3); }
+;
+
attribute:
- T_ATTRIBUTE attribute_decl { $$ = $2; }
+ T_ATTRIBUTE attribute_group possible_comma ']' { $$ = $2; }
;
attributes:
diff --git a/Zend/zend_language_scanner.l b/Zend/zend_language_scanner.l
index ee88282fd5..b00e4e3edb 100644
--- a/Zend/zend_language_scanner.l
+++ b/Zend/zend_language_scanner.l
@@ -1411,7 +1411,8 @@ NEWLINE ("\r"|"\n"|"\r\n")
RETURN_TOKEN_WITH_IDENT(T_RETURN);
}
-<ST_IN_SCRIPTING>"@@" {
+<ST_IN_SCRIPTING>"#[" {
+ enter_nesting('[');
RETURN_TOKEN(T_ATTRIBUTE);
}