rfc:attributes
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
rfc:attributes [2016/04/25 14:17] – dmitry | rfc:attributes [2017/09/22 13:28] (current) – external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== PHP RFC: Attributes ====== | ====== PHP RFC: Attributes ====== | ||
- | * Version: | + | * Version: |
* Date: 2016-04-21 | * Date: 2016-04-21 | ||
* Author: Dmitry Stogov, dmitry@zend.com | * Author: Dmitry Stogov, dmitry@zend.com | ||
- | * Status: | + | * Status: |
* First Published at: http:// | * First Published at: http:// | ||
===== Introduction ===== | ===== Introduction ===== | ||
- | Attributes (or annotation) is a form of syntactic metadata that can be added to language classes, functions, etc. PHP offers only a single form of such metadata - doc-comments. This is just a string and to keep some structured information, | + | Attributes (or annotations) are a form of syntactic metadata that can be added to language classes, functions, etc. PHP offers only a single form of such metadata - doc-comments. This is just a string and to keep some structured information, |
- | Many languages like Java, C#, Hack, etc provide a simpler way. They allow definition of structured meta-information through small syntax extension. | + | Many languages like Java, C#, Hack, etc provide a simpler way. They allow the definition of structured meta-information through small syntax extension. |
===== Proposal ===== | ===== Proposal ===== | ||
==== Attribute Syntax ==== | ==== Attribute Syntax ==== | ||
- | < | + | < |
<code php> | <code php> | ||
Line 22: | Line 22: | ||
</ | </ | ||
- | Each attribute definition construct may also define one or few named attributes, each attribute may be used without | + | Each attribute definition construct may also define one or more named attribute, which may be used with no value, |
< | < | ||
< | < | ||
{ "," | { "," | ||
- | < | + | <namespace-name> |
< | < | ||
</ | </ | ||
Line 38: | Line 38: | ||
</ | </ | ||
- | It's not possible to use the same attribute name for the same definition | + | It's not possible to use the same attribute name more than once on the same definition, however, it's possible to use multiple attribute values |
<code php> | <code php> | ||
Line 50: | Line 50: | ||
==== Arbitrary PHP Expressions as Attribute Values (AST attributes) ==== | ==== Arbitrary PHP Expressions as Attribute Values (AST attributes) ==== | ||
- | Except for simple scalars, attribute values may be represented with any valid PHP expression. | + | Other than simple scalars, attribute values may be represented with any valid PHP expression. |
<code php> | <code php> | ||
Line 58: | Line 58: | ||
</ | </ | ||
- | In this case, internally, the value of attribute is kept as an Abstract Syntax Tree, and we will able to read every individual node of this tree separately. This approach implies usage of the same PHP syntax for meta data and eliminates need for separate parser. | + | In this case, internally, the value of the attribute is kept as an Abstract Syntax Tree, and the user will have the ability |
- | The native usage of AST is not especially necessary. It's also possible to use plain strings and transform | + | The native usage of an AST is not especially necessary. It's also possible to use plain strings and then transform them into AST at user level, through |
<code php> | <code php> | ||
Line 67: | Line 67: | ||
} | } | ||
$r = new ReflectionFunction(" | $r = new ReflectionFunction(" | ||
- | $ast = ast\parse_code($r-> | + | $ast = ast\parse_code($r-> |
</ | </ | ||
==== Reflection ==== | ==== Reflection ==== | ||
- | Few reflection | + | Reflection |
<code php> | <code php> | ||
Line 81: | Line 81: | ||
</ | </ | ||
- | These functions return empty array if there were no attributes defined. Otherwise they return array with attribute names as keys and nested arrays as corresponding values. Attributes without values represented by empty arrays, attributes with single value by arrays with single element, etc. | + | These functions return empty array if there were no attributes defined. Otherwise, they return |
<code php> | <code php> | ||
Line 111: | Line 111: | ||
==== AST Representation ==== | ==== AST Representation ==== | ||
- | While internally AST is stored in native zend_ast format, Reflection*:: | + | While internally AST is stored in native zend_ast format, Reflection*:: |
<code php> | <code php> | ||
Line 182: | Line 182: | ||
} | } | ||
</ | </ | ||
+ | |||
+ | [[https:// | ||
==== Use Cases ==== | ==== Use Cases ==== | ||
- | With attributes it's extremely simple to mark some functions with some specific | + | With attributes, it's extremely simple to mark some functions with some specific |
<code php> | <code php> | ||
Line 199: | Line 201: | ||
</ | </ | ||
- | Attributes may be used provide | + | Attributes may be used as a base level for an annotation system similar to Doctrine, where each attribute is represented by an object of corresponding class that perform validation and other actions. |
<code php> | <code php> | ||
Line 266: | Line 268: | ||
==== Special Attributes ==== | ==== Special Attributes ==== | ||
- | Attribute names starting with " | + | < |
- | ==== Criticism and Alternative | + | ==== Criticism and Alternative |
- | Today we use single doc-comments for any kind of meta-information, | + | === Doc-comments === |
+ | |||
+ | Today we are using single doc-comments for any kind of meta-information, | ||
<code php> | <code php> | ||
Line 305: | Line 309: | ||
</ | </ | ||
- | This approach works, but PHP itself | + | This approach works, but PHP itself |
e.g. to check " | e.g. to check " | ||
It might be possible to make PHP parse existing doc-comments and keep information as structured attributes, but we would need to invoke additional parser for each doc-comment; | It might be possible to make PHP parse existing doc-comments and keep information as structured attributes, but we would need to invoke additional parser for each doc-comment; | ||
+ | |||
+ | === Full Featured Annotation System (like Doctrine) === | ||
+ | |||
+ | This RFC proposes only base PHP attribute functionality. It doesn' | ||
+ | |||
+ | <code php> | ||
+ | /** | ||
+ | * @Block( | ||
+ | * id = " | ||
+ | * | ||
+ | * ) | ||
+ | */ | ||
+ | |||
+ | << | ||
+ | " | ||
+ | " | ||
+ | ]))>> | ||
+ | class PageTitleBlock { | ||
+ | } | ||
+ | |||
+ | function TranslateDrupalAttribute($value) { | ||
+ | if ($value instanceof \ast\Node) { | ||
+ | if ($value-> | ||
+ | $a = $value-> | ||
+ | if (is_string($a) && class_exists($a)) { | ||
+ | $value = new $a; | ||
+ | } else if ($a instanceof \ast\Node && | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | $args = $a-> | ||
+ | if ($args instanceof ast\Node && $args-> | ||
+ | $obj = new $a-> | ||
+ | foreach ($args-> | ||
+ | if ($arg instanceof ast\Node && | ||
+ | $arg-> | ||
+ | count($arg-> | ||
+ | is_string($arg-> | ||
+ | $name = $arg-> | ||
+ | $val = $arg-> | ||
+ | if ($val instanceof ast\Node) { | ||
+ | $obj-> | ||
+ | } else { | ||
+ | $obj-> | ||
+ | } | ||
+ | } else { | ||
+ | throw DrupalAnnotationError(" | ||
+ | } | ||
+ | } | ||
+ | } else { | ||
+ | $name = $a-> | ||
+ | $obj = new $name($args); | ||
+ | } | ||
+ | $value = $obj; | ||
+ | } else { | ||
+ | throw DrupalAnnotationError(" | ||
+ | } | ||
+ | } else { | ||
+ | throw DrupalAnnotationError(" | ||
+ | } | ||
+ | } | ||
+ | return $value; | ||
+ | } | ||
+ | |||
+ | function GetDrupalAnnotations($class_name) { | ||
+ | $reflClass = new \ReflectionClass($class_name); | ||
+ | $attrs = $reflClass-> | ||
+ | $ret = []; | ||
+ | foreach ($attrs as $name => $values) { | ||
+ | if ($name == " | ||
+ | foreach ($values as & | ||
+ | $ret[] = TranslateDrupalAttribute($value); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | return $ret; | ||
+ | } | ||
+ | |||
+ | class Block {} | ||
+ | class Translation { | ||
+ | public $text; | ||
+ | function __construct($text) { | ||
+ | $this-> | ||
+ | } | ||
+ | } | ||
+ | |||
+ | var_dump(GetDrupalAnnotations(" | ||
+ | </ | ||
+ | |||
+ | < | ||
+ | array(1) { | ||
+ | [0]=> | ||
+ | object(Block)# | ||
+ | [" | ||
+ | string(21) " | ||
+ | [" | ||
+ | object(Translation)# | ||
+ | [" | ||
+ | string(13) "Site branding" | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | === ' | ||
+ | |||
+ | ' | ||
+ | |||
+ | === Naming (attributes or annotations) === | ||
+ | |||
+ | Different programming languages use different terms for similar features. Some use annotation, some attributes. I prefer name " | ||
===== Backward Incompatible Changes ===== | ===== Backward Incompatible Changes ===== | ||
Line 321: | Line 440: | ||
==== To Existing Extensions ==== | ==== To Existing Extensions ==== | ||
- | [[https:// | + | [[https:// |
==== To Opcache ==== | ==== To Opcache ==== | ||
Line 337: | Line 456: | ||
* < | * < | ||
* < | * < | ||
- | * It may be useful to optionally allow some extra special character e.g. < | + | * <del>It may be useful to optionally allow some extra special character e.g. < |
* < | * < | ||
+ | * < | ||
| | ||
===== Proposed Voting Choices ===== | ===== Proposed Voting Choices ===== | ||
- | This RFC modifies the PHP language syntax | + | The voting started on May 10th, 2016 and will close on May 24th, 2016. |
+ | |||
+ | <doodle title=" | ||
+ | * Yes | ||
+ | * No | ||
+ | </ | ||
+ | |||
+ | ---- | ||
- | In addition, allow <php-expression> | + | <doodle title=" |
+ | * valid PHP expression (internally represented as AST) | ||
+ | * valid PHP constant (number or string) | ||
+ | </ | ||
===== Patches and Tests ===== | ===== Patches and Tests ===== | ||
Line 357: | Line 487: | ||
* [[https:// | * [[https:// | ||
* [[https:// | * [[https:// | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
- | ===== Rejected Features ===== | ||
- | Keep this updated with features that were discussed on the mail lists. |
rfc/attributes.1461593842.txt.gz · Last modified: 2017/09/22 13:28 (external edit)