rfc:attributes_v2
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision | ||
rfc:attributes_v2 [2020/04/17 11:25] – beberlei | rfc:attributes_v2 [2020/05/04 12:00] – Closed vote beberlei | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== PHP RFC: Attributes v2 ====== | ====== PHP RFC: Attributes v2 ====== | ||
- | * Version: 0.4 | + | * Version: 0.5 |
* Date: 2020-03-09 | * Date: 2020-03-09 | ||
* Author: Benjamin Eberlei (beberlei@php.net), | * Author: Benjamin Eberlei (beberlei@php.net), | ||
- | * Status: | + | * Status: |
* First Published at: http:// | * First Published at: http:// | ||
* Implementation: | * Implementation: | ||
Line 39: | Line 39: | ||
< | < | ||
- | attributes may be applied to many things in the language | + | attributes may be applied to many things in the language: |
* functions (including closures and short closures) | * functions (including closures and short closures) | ||
Line 47: | Line 47: | ||
* class methods | * class methods | ||
* function/ | * function/ | ||
+ | |||
+ | Examples: | ||
+ | |||
+ | <code php> | ||
+ | << | ||
+ | class Foo | ||
+ | { | ||
+ | << | ||
+ | public const FOO = ' | ||
+ | |||
+ | << | ||
+ | public $x; | ||
+ | |||
+ | << | ||
+ | public function foo(<< | ||
+ | } | ||
+ | |||
+ | $object = new << | ||
+ | |||
+ | << | ||
+ | function f1() { } | ||
+ | |||
+ | $f2 = << | ||
+ | |||
+ | $f3 = << | ||
+ | </ | ||
Attributes are added before the declaration they belong to, similar to doc-block comments. They can be declared **before** or **after** a doc-block comment that documents a declaration. | Attributes are added before the declaration they belong to, similar to doc-block comments. They can be declared **before** or **after** a doc-block comment that documents a declaration. | ||
<code php> | <code php> | ||
- | <<...>> | + | <<ExampleAttribute>> |
- | <<...>> | + | /** docblock */ |
+ | <<AnotherExampleAttribute>> | ||
function foo() {} | function foo() {} | ||
</ | </ | ||
Line 71: | Line 98: | ||
The same attribute name can be used more than once on the same declaration. | The same attribute name can be used more than once on the same declaration. | ||
- | Sementically | + | Attributes can also be declared on the same line: |
+ | |||
+ | <code php> | ||
+ | << | ||
+ | function foo() {} | ||
+ | </ | ||
+ | |||
+ | Semantically | ||
with the attribute name and passing arguments to the constructor. | with the attribute name and passing arguments to the constructor. | ||
Line 212: | Line 246: | ||
**Note:** This is intentionally different from the previous Attributes RFC where an object | **Note:** This is intentionally different from the previous Attributes RFC where an object | ||
with ast\node was returned. | with ast\node was returned. | ||
+ | |||
+ | The parser understands the context to differentiate attributes from bitshifts in constant ASTs. | ||
+ | |||
+ | <code php> | ||
+ | << | ||
+ | function foo() {} | ||
+ | </ | ||
==== Reflection ==== | ==== Reflection ==== | ||
Line 238: | Line 279: | ||
<code php> | <code php> | ||
- | $attributes = $reflectionFunction-> | + | $attributes = $reflectionFunction-> |
+ | | ||
+ | | ||
+ | ); | ||
</ | </ | ||
Line 248: | Line 292: | ||
public function getName(): string | public function getName(): string | ||
public function getArguments(): | public function getArguments(): | ||
- | public function | + | public function |
} | } | ||
</ | </ | ||
Line 254: | Line 298: | ||
Because validation of attributes is only performed during | Because validation of attributes is only performed during | ||
- | // | + | // |
declare the attribute class. | declare the attribute class. | ||
from // | from // | ||
Line 283: | Line 327: | ||
var_dump($attributes[0]-> | var_dump($attributes[0]-> | ||
var_dump($attributes[0]-> | var_dump($attributes[0]-> | ||
- | var_dump($attributes[0]-> | + | var_dump($attributes[0]-> |
} | } | ||
Line 486: | Line 530: | ||
foreach ($attributes as $listenerAttribute) { | foreach ($attributes as $listenerAttribute) { | ||
/** @var $listener Listener */ | /** @var $listener Listener */ | ||
- | $listener = $listenerAttribute-> | + | $listener = $listenerAttribute-> |
// with $listener instanceof Listener attribute, | // with $listener instanceof Listener attribute, | ||
Line 524: | Line 568: | ||
Doctrine or any userland library can utilize the name filter with a parent class to fetch | Doctrine or any userland library can utilize the name filter with a parent class to fetch | ||
- | only attributes they are interested in: | + | only attributes they are interested in. With the flexibility in the proposed Reflection API, Doctrine (or any other userland |
+ | annotation/ | ||
+ | attributes by adding their own logic on top wihout PHP attributes getting in | ||
+ | the way. | ||
+ | |||
+ | Here is a complex example of an object using Doctrine Annotations and the proposed Attributes side by side to implement the same thing: | ||
<code php> | <code php> | ||
- | namespace | + | <?php |
+ | use Doctrine\ORM\Attributes as ORM; | ||
+ | use Symfony\Component\Validator\Constraints as Assert; | ||
- | abstract class Annotation { | + | << |
- | class TARGET_CLASS = 1; | + | /** @ORM\Entity */ |
- | class TARGET_PROPERTY = 2; | + | class User |
- | + | ||
- | public $target = self:: | + | |
- | + | ||
- | final public function __construct(array $values = []) { | + | |
- | foreach ($values as $key => $value) { | + | |
- | $this->$key = $value; | + | |
- | } | + | |
- | } | + | |
- | } | + | |
- | + | ||
- | class AnnotationReader | + | |
{ | { | ||
- | | + | |
- | $doctrineAnnotations = []; | + | << |
+ | | ||
- | foreach ($reflection-> | + | /** |
- | // filter out any that doesn't extend Doctrine's annotation base class | + | * @ORM\Column(type=" |
- | | + | * @Assert\Email(message=" |
- | | + | */ |
- | } | + | << |
+ | << | ||
+ | | ||
- | $annotation | + | /** |
+ | * @ORM\Column(type=" | ||
+ | * @Assert\Range( | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | * ) | ||
+ | */ | ||
+ | << | ||
+ | << | ||
+ | protected $height; | ||
- | | + | |
- | // getClassAnnotations requires all annotations to be allowed on a class | + | * @ORM\ManyToMany(targetEntity="Phonenumber") |
- | if (($annotation-> | + | * @ORM\JoinTable(name=" |
- | throw new \RuntimeException(get_class($annotation) . " | + | |
- | | + | * inverseJoinColumns={@ORM\JoinColumn(name="phonenumber_id", referencedColumnName=" |
- | + | * ) | |
- | | + | */ |
- | } | + | << |
- | + | << | |
- | | + | << |
- | | + | |
+ | private $phonenumbers; | ||
} | } | ||
</ | </ | ||
- | With this flexibility in the Reflection API, Doctrine (or any other userland | + | The attributes approach is a bit limited, because it doesn' |
- | annotation/attributes | + | |
- | attributes by adding their own logic on top wihout | + | |
- | the way. | + | |
[[https:// | [[https:// | ||
Line 697: | Line 749: | ||
* Other languages such as Go have simple but powerful serialization from XML/JSON to objects and back. The combination of typed properties an attributes puts this in reach for core or a PHP extension to implement. | * Other languages such as Go have simple but powerful serialization from XML/JSON to objects and back. The combination of typed properties an attributes puts this in reach for core or a PHP extension to implement. | ||
* An alternative " | * An alternative " | ||
- | * Extending userland attributes to allow declaring which target they are allowed to be declared on including validation of those targets in // | + | * Extending userland attributes to allow declaring which target they are allowed to be declared on including validation of those targets in // |
- | ===== Proposed | + | ===== Voting ===== |
- | * Accept PHP Attributes v2 into core? 2/3 majority | + | <doodle title=" |
- | * Which syntax to use for attributes? "<<>> | + | |
+ | * No | ||
+ | </ | ||
+ | |||
+ | Secondary vote (choice with the most votes is picked): | ||
+ | |||
+ | <doodle title=" | ||
+ | | ||
+ | | ||
+ | </ | ||
+ | |||
+ | Vote closes on May 4th, 12:00 UTC. | ||
===== Patches and Tests ===== | ===== Patches and Tests ===== | ||
Line 751: | Line 814: | ||
* Changed validation of compiler attributes to use a C callback instead of instantiating object | * Changed validation of compiler attributes to use a C callback instead of instantiating object | ||
* Offer alternative syntax " | * Offer alternative syntax " | ||
+ | |||
+ | 0.5: | ||
+ | |||
+ | * Rename ReflectionAttribute:: | ||
rfc/attributes_v2.txt · Last modified: 2020/08/01 23:38 by carusogabriel