This is an old revision of the document!
PHP RFC: Annotations
- Version: 0.1
- Date: 2019-02-05
- Author: Michał Brzuchalski michal.brzuchalski@gmail.com
- Status: Draft
- First Published at: http://wiki.php.net/rfc/annotations_v2
Introduction
Annotation is a form of syntactic metadata that can be added to source code. Annotations can be embedded in and read using reflection mechanism. Annotations are known from Java or so-called Attributes in C# and can be retained by VM at run-time and read via reflection. Annotations can be placed in classes, methods, properties and functions.
PHP offers only a single form of such metadata - doc-comments. In userland, there exist some annotation reader libraries like Doctrine Annotations which is widely used for eg. to express object-relational mapping metadata.
Proposal
Proposal of this RFC is to provide annotations with @
prefix in the place
the're declared like:
@AnnotationName("value", namedParamter=true, embeded=@EmbededAnnotation)
Which can be used to annotate classes, properties, methods and functions.
They look similar to new object instantiation but there is a wide range of inhibitions.
Annotations can have named and/or unnamed parameters, they're name can be imported using use
statement same way as class names but the place they're declared must use @
prefix.
The same as instantiating new object parenthesis is not obligatory if there are no parameters to pass. Unnamed parameters must exist at the beginning of parameters list and they must meet constructor parameter requirements.
use ORM\Entity; use ORM\Id; use ORM\Column; @Entity @Table("foo") class Foo { @Id @Column("id", type="uuid") private $id; }
use MVC\Route; class FooController { @Route("/api/foo", methods=["POST"], name="foo_create") public function create(Request $request): Response { // specific implementation } }
Built in annotations
@Annotation
Annotation classes have to contain a @Annotation
.
@Annotation class MyAnnotation { // some code }
@Target
@Target
annotation indicates the kinds of the class element or a function which an annotation type is applicable.
Then you could define one or more targets:
* CLASS
allowed before the class declaration
* PROPERTY
allowed before class property declaration
* METHOD
allowed before the class method declaration
* FUNCTION
allowed before the function declaration
* ALL
allowed in all cases, also default value
* ANNOTATION
allowed before annotation class declaration
@Repeatable
@Repeatable
annotation indicates the annotation may be repeated multiple times when annotating.
@Inherited
@Inherited
annotation can be used as meta-annotation on the other user-defined annotation classes.
When such user-defined annotations are used on superclass, they are automatically inherited to subclasses.
@Annotation class MyAnnotation {} @Annotation @Inherited class MyInheritedAnnotation {} @MyAnnotation @MyInheritedAnnotation class Foo {} class Bar extends Foo {} $refl = new ReflectionClass(Bar::class); $classAnnotations = $refl->getAnnotations(); // will include @MyInheritedAnnotation only
Examples
Custom annotations
Using annotations
use Example\MyAnnotation; use Example\MyEmbededAnnotation; @MyAnnotation( myProperty="value", myArrayProperty=[1, 3.14, true, "string", DIRECTORY_SEPARATOR], myEmbeded=@MyEmbededAnnotation() ) class Foo { @MyPropertyAnnotation private $property; @MyMethodAnnotation("value") public function bar() {} }
Declaring custom annotations
namespace Example; @Annotation @Target("class") class MyAnnotation { @Required public string $myProperty; public array $myArrayProperty = []; public MyEmbededAnnotation $myEmbeded; } @Annotation @Target(["class", "annotation"]) class MyEmbededAnnotation { } @Annotation @Target("property") class MyPropertyAnnotation { } @Annotation @Target("method") class MyMethodAnnotation { public string $value; public function __construct(string $value) { $this->value = $value; } }
Reading annotations
$refl = new ReflectionClass(Foo::class); $classAnnotations = $refl->getAnnotations(); $propertyAnnotations = $refl->getProperty('property')->getAnnotations(); $methodAnnotations = $refl->getMethod('foo')->getAnnotations();
Benefits
Caching
Annotations are cached with source code in OPCache. Which is different than userland implementations which are stored cached outside of source code. This means they don't need invoking reread after cache invalidation.
Live with the code
Provided annotations live with the code so it's easy to enable/disable behaviour of components which use their metadata.
For eg. @Route
in MVC style application is metadata for controller method which is used by the routing component.
Which means any changes to the controller implementation or it's routing metadata lives in one place and therefore can be for eg. commented out with the controller method.
IDE support
Provided annotations can be verified in IDE. The IDE can also provide auto-completion support or a sort of validation.
Critique
TBD
Backward Incompatible Changes
None.
Proposed PHP Version(s)
Proposed version is next PHP 7.x or PHP 8.
RFC Impact
To SAPIs
None.
To Existing Extensions
None.
To Opcache
Probably yes.
Proposed Voting Choices
As this is a language change, a 2/3 majority is required. The vote is a straight Yes/No vote for accepting the RFC and merging the patch.
Patches and Tests
TBD.
Implementation
TBD.
References
TBD