====== Request for Comments: Annotations in DocBlock ====== * Version: 1.0 * Date: 2011-05-11 * Author: Guilherme Blanco , Pierrick Charron * Status: Inactive * First Published at: http://wiki.php.net/rfc/annotations-in-docblock ===== Introduction ===== Many languages currently support metadata information. This RFC exposes an idea about how can it be implemented in PHP, providing a powerful tool that many applications can take advantage of. ==== Why do we need Class Metadata? ==== Frameworks in general rely on metadata information in order to correctly work. They can use it for many purposes: * **phpUnit** Providing meta functionality for test cases, examples: @dataProvider for test data iteration, @expectedException for catching exceptions, etc. * **Doctrine** For Object-Relational mapping, examples: @Entity, @OneToOne, @Id, etc. * **Zend Framework Server classes** Used to automate mappings for XML-RPC, SOAP, etc. * **FLOW3** 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:Traits]]), etc. Also, any Framework could take advantage of it somehow. So, any meta mapping injection could be easily achieved via the implementation of a centralized Annotations support. The .NET framework uses Data Annotation: [[http://www.asp.net/mvc/tutorials/validation-with-the-data-annotation-validators-cs]] 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). ===== Common Misconceptions ===== Metadata mapping is commonly referred an feature that cannot be used widely, so its implementation is useless. 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://willcode4beer.com/design.jsp?set=annotations_gotchas_best_practices]] [[http://www.softwarereality.com/programming/annotations.jsp]] ===== Tokens choice ===== First thing to be decided is how would the tokens be arranged to categorize an Annotation. * Java uses [[http://en.wikipedia.org/wiki/Java_annotation|Annotations]] * C# uses [[http://en.wikipedia.org/wiki/.NET_metadata|Attributes]] When using meta mapping, less characters is preferred to speed up its construction. Since it's a de-facto standard on docblocks to use @, we'll stick to this one for compatibility. ===== How to define annotations ===== **This section still needs expand on subject, since it's just an idea** /** * Foo class. * * @Entity {"repositoryClass": "FooRepository"} * @Table {"name": "foos"} * * @author "Guilherme Blanco" */ class Foo { // ... } The basic idea is to define an entry name "@[a-zA-Z_]{1}[a-zA-Z0-9_]*" and then a JSON as value. That way, we could abstract the ReflectionAnnotation class as a generic implementation: class ReflectionAnnotation { private $value; public function __construct(\stdClass $value) { $this->value = $value; } public function getValue() { return $this->value; } } And have a public Reflection API: class ReflectionFunction { // ... public function getAnnotations(); public function getAnnotation($name); public function hasAnnotation($name); } class ReflectionClass { // ... public function getAnnotations(); public function getAnnotation($name); public function hasAnnotation($name); } class ReflectionProperty { // ... public function getAnnotations(); public function getAnnotation($name); public function hasAnnotation($name); } class ReflectionMethod { // ... public function getAnnotations(); public function getAnnotation($name); public function hasAnnotation($name); } class ReflectionParameter { // ... public function getAnnotations(); public function getAnnotation($name); public function hasAnnotation($name); } Please notice that ReflectionParameter would now accept docblock to support Annotations. This is something that still needs to be discussed. ===== Consuming ===== $reflClass = new \ReflectionClass('Foo'); var_dump($reflClass->getAnnotations()); /* array(3) { ["Entity"]=> object(ReflectionAnnotation)#1 (1) { ["value"]=> object(stdClass)#1 (1) { ["repositoryClass"]=> string(13) "FooRepository" } } ["Table"]=> object(ReflectionAnnotation)#2 (1) { ["value"]=> object(stdClass)#1 (1) { ["name"]=> string(4) "foos" } } ["author"]=> object(ReflectionAnnotation)#3 (1) { ["value"]=> string(16) "Guilherme Blanco" } } */ ===== Patch ===== TBD ===== Changelog ===== * 2011-05-11 guilhermeblanco Initial RFC creation.