Annotation is a form of syntactic metadata that can be added to source code. Annotations can be embeded in and read using reflection mechanism. Annotations 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 exists some annotation reader libraries like Doctrine Annotations which is widely used for eg. to express object-relational mapping metadata.
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 exists at the begining 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
}
}
Annotation classes have to contain a @Annotation
.
@Annotation
class MyAnnotation {
// some code
}
@Target
annotation indicates the kinds of class element or
function which an annotation type is applicable.
Then you could define one or more targets:
CLASS
allowed before class declarationPROPERTY
allowed before class property declarationMETHOD
allowed before class method declarationFUNCTION
allowed before function declarationALL
allowed in all cases, also default valueANNOTATION
allowed before annotation class declaration
@Repeatable
annotation indicates the annotation may be
repeated multiple times when annotating.
@Inherited
annotation can be used as meta-annotation on
the other user defined annotation classes. When such user
defined annotations are used on super class, they are
automatically inherited to sub classes.
@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
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();
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.
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 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.
Provided annotations can be verified in IDE. The IDE can also provide auto-completion support or sort of validation.
None.
PHP 7.4
None.
None.
Yes.
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.
TBD.
TBD.
Missing parts: