rfc:annotations-in-docblock

Request for Comments: 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 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.

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.
rfc/annotations-in-docblock.txt · Last modified: 2014/04/09 00:49 by levim