rfc:annotations
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
rfc:annotations [2010/09/15 00:54] – pierrick | rfc:annotations [2017/09/22 13:28] (current) – external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== Request for Comments: Class Metadata ====== | ====== Request for Comments: Class Metadata ====== | ||
+ | |||
* Version: 1.0 | * Version: 1.0 | ||
* Date: 2010-08-24 | * Date: 2010-08-24 | ||
* Author: Guilherme Blanco < | * Author: Guilherme Blanco < | ||
- | * Status: | + | * Status: |
* First Published at: http:// | * First Published at: http:// | ||
- | |||
===== Introduction ===== | ===== Introduction ===== | ||
Line 16: | Line 16: | ||
* **phpUnit** Providing meta functionality for test cases, examples: @dataProvider for test data iteration, @expectedException for catching exceptions, etc. | * **phpUnit** Providing meta functionality for test cases, examples: @dataProvider for test data iteration, @expectedException for catching exceptions, etc. | ||
- | * **phpDoc** Providing useful information for API generation, examples: @author, @param, @return, etc. | ||
* **Doctrine** For Object-Relational mapping, examples: @Entity, @OneToOne, @Id, etc. | * **Doctrine** For Object-Relational mapping, examples: @Entity, @OneToOne, @Id, etc. | ||
* **Zend Framework Server classes** Used to automate mappings for XML-RPC, SOAP, etc. | * **Zend Framework Server classes** Used to automate mappings for XML-RPC, SOAP, etc. | ||
+ | * **TYPO3** for dependency injection and validation | ||
+ | * **Symfony2** for routing rules | ||
* **Others** One clear thing that comes to my mind is Validation, Functional Behavior injection (which could take advantage of [[rfc: | * **Others** One clear thing that comes to my mind is Validation, Functional Behavior injection (which could take advantage of [[rfc: | ||
So, any meta mapping injection could be easily achieved via the implementation of a centralized Annotations support. | So, any meta mapping injection could be easily achieved via the implementation of a centralized Annotations support. | ||
+ | |||
+ | The .NET framework uses Data Annotation: | ||
+ | [[http:// | ||
+ | |||
+ | An advantage here is the .net framework will process some annotations and inject behavior into the compiled source code. | ||
+ | |||
+ | It's important to note that annotations exist in java and .net but many strong use cases exist in these languages to provide hints to the compiler (@NotNull). | ||
+ | |||
+ | These types of use cases (hints to the Zend lexer/ | ||
===== Common Misconceptions ===== | ===== Common Misconceptions ===== | ||
Metadata mapping is commonly referred an feature that cannot be used widely, so its implementation is useless. | Metadata mapping is commonly referred an feature that cannot be used widely, so its implementation is useless. | ||
- | As pointed previously, there' | + | As pointed previously, there are many use cases for this support. |
+ | |||
+ | Though useful, the good and bad use cases of annotations are heavily debated (religiously): | ||
+ | |||
+ | [[http:// | ||
+ | |||
+ | [[http:// | ||
===== Proposal ===== | ===== Proposal ===== | ||
Line 36: | Line 53: | ||
When using meta mapping, less characters is preferred to speed up its construction. | When using meta mapping, less characters is preferred to speed up its construction. | ||
- | PHP Annotation could be simplified into this EBNF: | + | PHP Annotation could be simplified into this EBNF (Extended Backus-Naur Form): |
< | < | ||
Annotations | Annotations | ||
- | Annotation | + | Annotation |
- | AnnotationName | + | AnnotationName |
QualifiedName | QualifiedName | ||
- | AliasedName | ||
NameSpacePart | NameSpacePart | ||
SimpleName | SimpleName | ||
Alias ::= identifier | Alias ::= identifier | ||
- | Values | + | Values |
- | Value ::= PlainValue | FieldAssignment | + | Value ::= integer | string | float | boolean | Array | Annotation |
- | PlainValue | + | |
- | FieldAssignment ::= FieldName " | + | |
- | FieldName | + | |
Array ::= " | Array ::= " | ||
ArrayEntry | ArrayEntry | ||
- | KeyValuePair | + | KeyValuePair |
Key ::= string | integer | Key ::= string | integer | ||
</ | </ | ||
- | With identifier being the terminal: [a-zA-Z_][a-zA-Z0-9_]* | + | With integer, string, float, boolean, float and identifier being the terminals. Identifier: [a-zA-Z_][a-zA-Z0-9_]* |
- | The annotation can be a composite of a start/end tokens. Here is an example of PHP Annotations: | + | |
+ | The start/end tokens | ||
+ | Here is an example of PHP Annotations: | ||
< | < | ||
- | [Entity(tableName=" | + | <Entity(" |
class User | class User | ||
{ | { | ||
- | | + | |
- | | + | |
- | | + | |
protected $id; | protected $id; | ||
// ... | // ... | ||
- | | + | |
- | [JoinTable( | + | |
- | name=" | + | |
- | joinColumns=array( | + | |
- | [JoinColumn(name=" | + | |
- | ), | + | |
- | inverseJoinColumns=array( | + | |
- | [JoinColumn(name=" | + | |
- | ) | + | |
- | )] | + | |
protected $Phonenumbers; | protected $Phonenumbers; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | One point to notice is that nested Annotations are allowed. This is an important feature against key=> | ||
+ | Here is a simple sample of usage: | ||
+ | |||
+ | <code php> | ||
+ | < | ||
+ | class User { | ||
+ | // ... | ||
} | } | ||
</ | </ | ||
The support is all done through the inclusion of a new class: ReflectionAnnotation. | The support is all done through the inclusion of a new class: ReflectionAnnotation. | ||
+ | |||
+ | |||
===== How to define Annotations ===== | ===== How to define Annotations ===== | ||
- | Annotations can be defined | + | Annotations can be defined |
- | ReflectionAnnotation is an abstract class the must be implemented in order to accept an Annotation definition. | + | ReflectionAnnotation is an interface that must be implemented in order to accept an Annotation definition. |
- | Once this class is extended, the subclass is ready to be used an an Annotation: | + | Once this class is extended, the subclass is ready to be used as an Annotation: |
<code php> | <code php> | ||
- | class Foo extends | + | class Foo implements |
+ | public $value; | ||
- | [Foo(true)] | + | public function __construct($value) |
+ | { | ||
+ | $this-> | ||
+ | } | ||
+ | } | ||
+ | |||
+ | <Foo(array(true))> | ||
class Bar { /* ... */ } | class Bar { /* ... */ } | ||
</ | </ | ||
- | Just extending the base class already allows you to define a unique value, accessible | + | To have access |
<code php> | <code php> | ||
Line 106: | Line 131: | ||
$reflAnnot = $reflClass-> | $reflAnnot = $reflClass-> | ||
- | echo $foo-> | + | echo $foo-> |
</ | </ | ||
To expand Annotations support, it is allowed to define other properties. | To expand Annotations support, it is allowed to define other properties. | ||
- | BY doing it, you can define Annotations and automatically defining values to them. | + | By doing it, you can define Annotations and automatically defining values to constructor. |
<code php> | <code php> | ||
namespace App\Annotation; | namespace App\Annotation; | ||
- | class Link extends | + | class Link implements |
public $url; | public $url; | ||
public $target; | public $target; | ||
+ | | ||
+ | public function __construct($url, | ||
+ | { | ||
+ | $this-> | ||
+ | $this-> | ||
+ | } | ||
} | } | ||
- | [App\Annotation\Link(url=" | + | namespace |
+ | |||
+ | <Annotation\Link(" | ||
class PHPWebsite { | class PHPWebsite { | ||
- | /* ... */ | + | // ... |
} | } | ||
</ | </ | ||
- | ===== How to retrieve Annotation information ===== | + | Please notice that Annotations can also take advantage of " |
+ | Example: | ||
- | Annotations are only useful if defined information can be retrieved somehow. | + | <code php> |
- | There are different ways to retrieve annotation information, | + | namespace Foo\Bar; |
- | ** The following explanation | + | < |
+ | < | ||
+ | class Playground { | ||
+ | // ... | ||
+ | } | ||
- | To define an Annotation that may be exported | + | // Exception points |
- | This is the general rule for Inherited annotations: | + | // \Exception points |
+ | </ | ||
- | ** [Inherited] annotations are not inherited when used to annotate anything other than a class. A class that implements one or more interfaces never inherits any annotations from the interfaces it implements. ** | + | ===== How to retrieve Annotation information ===== |
+ | Annotations are only useful if defined information can be retrieved somehow. | ||
Example: | Example: | ||
<code php> | <code php> | ||
- | [Inherited] | + | class Author implements |
- | class Foo extends | + | public $name; |
+ | |||
+ | public function __construct($name) { $this-> | ||
+ | } | ||
- | class Bar extends \ReflectionAnnotation | + | < |
- | + | class MyTest | |
- | [Foo] | + | < |
- | [Bar] | + | |
- | class A {} | + | { |
+ | // ... | ||
+ | } | ||
+ | } | ||
- | class B extends | + | class ExtendedTest |
</ | </ | ||
Line 156: | Line 202: | ||
<code php> | <code php> | ||
- | $reflClassA = new \ReflectionClass(' | + | $reflClassA = new \ReflectionClass(' |
var_dump($reflClassA-> | var_dump($reflClassA-> | ||
/* | /* | ||
- | array(2) { | + | array(1) { |
- | ["Foo" | + | ["Author" |
- | object(Foo)#%d (1) { | + | object(Author)#%d (1) { |
- | ["value" | + | ["name" |
- | }, | + | |
- | [" | + | |
- | object(Bar)#%d (1) { | + | |
- | ["value"]=>NULL | + | |
} | } | ||
} | } | ||
*/ | */ | ||
- | $reflClassB | + | $reflMethodToString |
- | var_dump($reflClassB-> | + | var_dump($reflMethodToString-> |
/* | /* | ||
- | array(2) { | + | array(1) { |
- | ["Foo" | + | ["Author" |
- | object(Foo)#%d (1) { | + | object(Author)#%d (1) { |
- | ["value" | + | ["name" |
} | } | ||
+ | } | ||
+ | */ | ||
+ | |||
+ | $reflClassB = new \ReflectionClass(' | ||
+ | var_dump($reflClassB-> | ||
+ | /* | ||
+ | array(0) { | ||
} | } | ||
*/ | */ | ||
</ | </ | ||
- | The method `getAnnotations()` supports one of the three arguments: | + | Please notice that multiple instantiation |
+ | Also, the inheritance of Annotations is left for discussion too. This can be done by 2 different approaches: | ||
- | * \ReflectionAnnotation::ALL - Fetched both defined annotations + inherited ones | + | * Using an Annotation at the top of ReflectionAnnotation |
- | * \ReflectionAnnotation:: | + | * Using a different interface to be implemented. This was another approach that we considered, but left for discussion. |
- | * \ReflectionAnnotation:: | + | |
Another available method is to retrieve an specific Annotation: `getAnnotation($name)`, | Another available method is to retrieve an specific Annotation: `getAnnotation($name)`, | ||
Line 196: | Line 245: | ||
<code php> | <code php> | ||
- | + | interface | |
- | abstract class ReflectionAnnotation { | + | |
- | const INHERITED = 1; | + | |
- | const DECLARED | + | |
- | const ALL = 3; | + | |
- | + | ||
- | public $value | + | |
- | + | ||
- | public function __construct(Reflector $reflector, array $properties = null) { | + | |
- | if (is_array($properties)) { | + | |
- | foreach ($properties as $k => $v) { | + | |
- | $this-> | + | |
- | } | + | |
- | } | + | |
- | } | + | |
} | } | ||
Line 224: | Line 259: | ||
// ... | // ... | ||
- | public function getAnnotations($type = ReflectionAnnotation:: | + | public function getAnnotations(); |
- | public function getAnnotation($name, $type = ReflectionAnnotation:: | + | public function getAnnotation($name); |
- | public function hasAnnotation($name, $type = ReflectionAnnotation:: | + | public function hasAnnotation($name); |
} | } | ||
Line 238: | Line 273: | ||
class ReflectionMethod { | class ReflectionMethod { | ||
+ | // ... | ||
+ | |||
+ | public function getAnnotations(); | ||
+ | public function getAnnotation($name); | ||
+ | public function hasAnnotation($name); | ||
+ | } | ||
+ | |||
+ | class ReflectionParameter { | ||
// ... | // ... | ||
Line 248: | Line 291: | ||
===== BC breaks ===== | ===== BC breaks ===== | ||
- | * Creates | + | * Creates |
* None otherwise (no new keywords) | * None otherwise (no new keywords) | ||
+ | ===== To be discussed ===== | ||
+ | |||
+ | * Possible usage of " | ||
+ | * Tokens for start/end. Currently it's "<" | ||
+ | * Nested Annotation declaration: | ||
+ | * Multiple instantiations of Annotation classes on a same block. | ||
+ | * Inheritance of classes/ | ||
===== Patch ===== | ===== Patch ===== | ||
- | [[http:// | + | Patch : [[http:// |
+ | |||
+ | Tests : [[http:// | ||
===== Changelog ===== | ===== Changelog ===== | ||
Line 261: | Line 313: | ||
* 2010-08-24 guilhermeblanco Updated for a real doable support | * 2010-08-24 guilhermeblanco Updated for a real doable support | ||
* 2010-08-24 pierrick Add the patch | * 2010-08-24 pierrick Add the patch | ||
+ | * 2011-05-09 guilhermeblanco Updated patch with recent compatibility. Previous patch removed. New one should be added shortly. |
rfc/annotations.1284512049.txt.gz · Last modified: 2017/09/22 13:28 (external edit)