Skip to content

Commit

Permalink
Implement Shorter Attribute Syntax
Browse files Browse the repository at this point in the history
RFC: https://wiki.php.net/rfc/shorter_attribute_syntax

Closes GH-5796.

Co-authored-by: Martin Schröder <m.schroeder2007@gmail.com>
  • Loading branch information
2 people authored and nikic committed Jul 28, 2020
1 parent 44ad2db commit 470d169
Show file tree
Hide file tree
Showing 34 changed files with 144 additions and 112 deletions.
5 changes: 5 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ PHP 8.0 UPGRADE NOTES
Additionally, care should be taken that error messages are not displayed in
production environments, which can result in information leaks. Please
ensure that display_errors=Off is used in conjunction with error logging.
. Adding more than one @ operator to an expression is no longer supported,
since this syntax is now used for attributes (previously extra @ operators
had no effect).
RFC: https://wiki.php.net/rfc/shorter_attribute_syntax
. Inheritance errors due to incompatible method signatures (LSP violations)
will now always generate a fatal error. Previously a warning was generated
in some cases.
Expand Down Expand Up @@ -605,6 +609,7 @@ PHP 8.0 UPGRADE NOTES
. Added support for Attributes
RFC: https://wiki.php.net/rfc/attributes_v2
RFC: https://wiki.php.net/rfc/attribute_amendments
RFC: https://wiki.php.net/rfc/shorter_attribute_syntax
. Added support for constructor property promotion (declaring properties in
the constructor signature).
RFC: https://wiki.php.net/rfc/constructor_promotion
Expand Down
18 changes: 9 additions & 9 deletions Zend/tests/attributes/001_placement.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
4 changes: 2 additions & 2 deletions Zend/tests/attributes/002_rfcexample.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Attributes: Example from Attributes RFC
namespace My\Attributes {
use Attribute;

<<Attribute>>
@@Attribute
class SingleArgument {
public $argumentValue;

Expand All @@ -19,7 +19,7 @@ namespace My\Attributes {
namespace {
use My\Attributes\SingleArgument;

<<SingleArgument("Hello World")>>
@@SingleArgument("Hello World")
class Foo {
}

Expand Down
12 changes: 6 additions & 6 deletions Zend/tests/attributes/003_ast_nodes.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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);
Expand All @@ -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';
Expand All @@ -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));

Expand Down
10 changes: 5 additions & 5 deletions Zend/tests/attributes/004_name_resolution.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
}
}
Expand Down
20 changes: 10 additions & 10 deletions Zend/tests/attributes/005_objects.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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();
Expand All @@ -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();
Expand All @@ -36,7 +36,7 @@ try {

echo "\n";

$ref = new \ReflectionFunction(<<A1([])>> function () { });
$ref = new \ReflectionFunction(@@A1([]) function () { });

try {
$ref->getAttributes()[0]->newInstance();
Expand All @@ -46,7 +46,7 @@ try {

echo "\n";

$ref = new \ReflectionFunction(<<A2>> function () { });
$ref = new \ReflectionFunction(@@A2 function () { });

try {
$ref->getAttributes()[0]->newInstance();
Expand All @@ -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();
Expand All @@ -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();
Expand All @@ -87,7 +87,7 @@ echo "\n";

class A5 { }

$ref = new \ReflectionFunction(<<A5>> function () { });
$ref = new \ReflectionFunction(@@A5 function () { });

try {
$ref->getAttributes()[0]->newInstance();
Expand Down
16 changes: 8 additions & 8 deletions Zend/tests/attributes/006_filter.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand All @@ -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));
Expand Down
2 changes: 1 addition & 1 deletion Zend/tests/attributes/008_wrong_attribution.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Attributes: Prevent Attribute on non classes
--FILE--
<?php

<<Attribute>>
@@Attribute
function foo() {}
--EXPECTF--
Fatal error: Attribute "Attribute" cannot target function (allowed targets: class) in %s
22 changes: 12 additions & 10 deletions Zend/tests/attributes/009_doctrine_annotations_example.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +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;

/**
Expand All @@ -50,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;

/**
Expand All @@ -61,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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Attribute arguments support only const expressions.
--FILE--
<?php

<<A1(foo())>>
@@A1(foo())
class C1 { }

?>
Expand Down
8 changes: 4 additions & 4 deletions Zend/tests/attributes/011_inheritance.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ Attributes comply with inheritance rules.
--FILE--
<?php

<<A2>>
@@A2
class C1
{
<<A1>>
@@A1
public function foo() { }
}

Expand All @@ -17,7 +17,7 @@ class C2 extends C1

class C3 extends C1
{
<<A1>>
@@A1
public function bar() { }
}

Expand All @@ -37,7 +37,7 @@ echo "\n";

trait T1
{
<<A2>>
@@A2
public $a;
}

Expand Down

0 comments on commit 470d169

Please sign in to comment.