====== PHP RFC: Simple Annotations ======
* Version: 0.3
* Date: 2016-05-13
* Author: Rasmus Schultz, rasmus@mindplay.dk
* Status: Draft
* First Published at: http://wiki.php.net/rfc/simple-annotations
===== Introduction =====
This RFC proposes the introduction of simple value annotations - arbitrary values attached to classes and class members as meta-data, obtainable via reflection.
As an alternative proposal to [[https://wiki.php.net/rfc/attributes|attributes]], this proposal aims to fully leverage existing language features, in order to provide more flexibility, lessen the learning curve, and expose meta-data in a manner that is more immediately useful, without having to build any run-time facilities.
Compared with annotation systems such as [[https://github.com/doctrine/annotations|Doctrine Annotations]], this proposal does not attempt to define or enforce any domain rules - it does not define inheritance semantics, rules about applicable source-code elements, cardinality, or any other rules; these can be defined and implemented by userland packages.
===== Proposal =====
The proposed syntax of a single annotation is very simple:
"<<" ">>"
Any valid PHP expression is a valid annotation.
Any number of annotations may be placed in front of any of the following applicable declarations:
* ''class'', ''trait'' and ''interface'' declarations
* ''function'' and property declarations in classes/traits/interfaces
* anonymous ''function'' declarations
* anonymous ''class'' declarations (and their members)
* argument declarations of functions, methods and closures
Annotations are internally collected, for each annotated class or member, in a list which can be obtained via reflection.
The following trivial example annotates a class with a string and an array of numbers:
<< "Hello World" >>
<< [1, 2, 3] >>
class Hello
{}
The following example annotates an entity with a ''TableName'' instance, which might be consumed by a database abstraction:
class TableName
{
public $name;
public function __construct($name) {
$this->name = $name;
}
}
<< new TableName("users") >>
class User
{
// ...
}
$reflection = new ReflectionClass(User::class);
var_dump($reflection->getAnnotations());
Example output:
array(1) {
[0]=>
object(TableName)#1 (1) {
["name"]=>
string(5) "users"
}
}
Annotation expressions are not evaluated until reflection is invoked, and are evaluated only once and internally memoized upon the first call to ''getAnnotations()''.
==== Annotations are Context-free ====
By design, annotations expressions are evaluated individually in an empty scope - which means there is no access to variables in the parent class, file, local or global scope, e.g. no ''$this'', ''self'' or ''static''.
Annotations work consistently regardless of which source element they are applied to, and may be evaluated without first creating an object instance.
Annotations that do require context should explicitly ask for that context - for example, you could use an anonymous function, a ''callable'', or an anonymous class, to provide context via dependency injection.
==== Reflection API ====
The following classes will have an added ''getAnnotations()'' method:
* ''ClassReflection''
* ''ReflectionFunctionAbstract'' (''ReflectionFunction'' and ''ReflectionMethod'')
* ''ReflectionProperty''
* ''ReflectionParameter''
The ''getAnnotations()'' method has the following signature:
public function getAnnotations($filter = null) : array
The optional ''$filter'' argument, if given, filters the returned list of annotations as follows:
* If one of ''string'', ''int'', ''float'', ''bool'' are given, filters annotations using ''is_int()'', ''is_string()'', etc.
* If a fully-qualified class-name is given, filters annotations using ''instanceof''
If ''null'' is given (default) all annotations are returned.
These methods do not take into account inheritance - annotations belong to the actual *declaration*, not to an abstract *member*, and as such, traversing parent classes, interfaces, etc. is up to the consumer.
===== Backward Incompatible Changes =====
None.
===== Proposed PHP Version(s) =====
Next PHP 7.x.
===== RFC Impact =====
==== To SAPIs ====
TODO
==== To Existing Extensions ====
TODO
==== To Opcache ====
TODO
===== Open Issues =====
Make sure there are no open issues when the vote starts!
===== Unaffected PHP Functionality =====
Annotations are a new feature - it does not affect any existing functionality.
===== Out of Scope =====
It has been suggested that this RFC should reserve certain names for compiler directives, such as (for instance) the memoization-directive [[https://docs.hhvm.com/hack/attributes/special|supported by Hack]]. This proposal does not reserve any such names, because (as others pointed out during that discussion) these are not meta-data, but rather directives for the compiler, and such features ought to be supported directly by keywords or syntax rather than by magical meta-data.
===== Proposed Voting Choices =====
TODO State whether this project requires a 2/3 or 50%+1 majority (see [[voting]])
===== Patches and Tests =====
There is a draft with no available implementation at this time.
===== Implementation =====
TODO After the project is implemented, this section should contain
- the version(s) it was merged to
- a link to the git commit(s)
- a link to the PHP manual entry for the feature
===== References =====
* [[https://gist.github.com/mindplay-dk/ebd5e4f7da51da3c4e56232adef41b46|some notes in a gist]]
===== Rejected Features =====
None.