Symfony 4 was released on November 30th.
Update now to the best Symfony ever!

Symfony2: Annotations get better

Later today, I will release Symfony2 beta2. But first, I wanted to talk about a big change that landed into master yesterday. As you might know, Symfony2 uses annotations for Doctrine mapping information and validation configuration. Of course, it is entirely optional, and the same can be done with XML, YAML, or even PHP. But using annotations is convenient and allows you to define everything in the same file.

Symfony Standard Edition provides an even better support for annotations via two additional bundles: SensioFrameworkExtraBundle and JMSSecurityExtraBundle. They allow you to use annotations for controller configuration (routing, cache, security, template, ...).

To avoid ambiguities when different libraries/bundles define new annotations, you were required to use a configurable "prefix":

/**
 * @orm:Entity
 */
class User
{
    /**
     * @orm:Column(type="string", nullable=false)
     * @assert:NotBlank
     */
    private $name;
}

But several problems arose quite fast:

  • If you have a look at the Doctrine documentation, you will see that @Column is used instead of @orm:Column. That's because the prefix is optional. So, the Doctrine documentation does not use one, but Symfony2 forces you to use orm. Note that it is configurable, so you might use any other prefix (@doctrine:Column).

  • The annotation library did not play well with autoloading.

  • SensioFrameworkExtraBundle and JMSSecurityExtraBundle shared the same extra prefix, but it was a hack and it was not really scalable.

Johannes worked hard in the last few weeks to find an elegant solution to this problem. As each annotation is defined as a class, instead of using only the short class name, we have decided to use the fully qualified class name. It removes the need for arbitrary prefixes defined as a global configuration, avoids any ambiguities between libraries, and gets rid of the autoloading issue altogether:

/**
 * @Doctrine\ORM\Mapping\Entity
 */
class User
{
    /**
     * @Doctrine\ORM\Mapping\Column(type="string", nullable=false)
     * @Symfony\Component\Validator\Constraints\NotBlank
     */
    private $name;
}

Of course, using the FQCN everywhere is quite verbose but fortunately, PHP already has a solution via the use statement:

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Entity
 */
class User
{
    /**
     * @ORM\Column(type="string", nullable=false)
     * @Assert\NotBlank
     */
    private $name;
}

Annotations now feel more "native". If you want to use annotations outside of a Symfony2 context, have a look at the Doctrine Common repository (version 3.0).

Comments

Just to make it clear, this means that Symfony2 stable will come with Doctrine Common 3.x which is scheduled to be released end of June.
It's a little more code to write (and to remember!) but I see that this is necessary in the "big picture". Thanks for your hard work, I really begin to enjoy Symfony2 and I'm looking forward for the final release.
It's both easy and configurable. Great job, Johannes!
Can't help but feel there is a Lot more typing in SF2...

And still no default= option?!
Someone pointed me out that special characters in tag names might be and issue for DocBlock parsers.

Someone tried generating a documentation with such annotations included?
We will port this back to Doctrine 2.1 aswell, we already have a working implementation that has this features and is backwards compatible (i.e. allows to set @alias: aswell).

We havent discussed finally what features become deprecated and which will make the step to 3.0
Totally awesome! Great work Johannes
Looks great..

Although I've saw its now called 'Symfony Standard Edition'.

Please please please please please tell me that symfony isn't going to have a 'standard' and 'premium' edition...
The changes above can have influence on applications which parse DocBlocks as tag names are commonly defined as being alphanumeric.

I'd expect that parsers can adapt (except for perhaps the older ones) but a detailed specification of the new format is necessary. I know I wouldn't mind adapting DocBlox but I'd need the spec.

The format above also conflicts with efforts in Internals where a different format is proposed for a similar functionality. Perhaps you and Guillhermo can work together to come to a single standard?
I really like this and It improves the understanding of what is going on under the hood. Great job!
@Mike, Guilherme was also involved in the process of updating Doctrine Common to this new approach. We basically follow the EBNF that is detailed in Guilherme's first RFC with the exception that we do not use "" but "@" to mark annotations (https://wiki.php.net/rfc/annotations).
@Johannes: Guillhermo has written a new RFC (https://wiki.php.net/rfc/annotations-in-docblock) which differs from the format presented above.

For one it does not mention the use of non-alphanumeric character as tag names.

And additionally it present that content in the 'description' section of the tag; whilst the above code shows no space between the @tagname and the (content). This does not help when generating documentation as a tag is no longer an identifier but now has contextual meaning and thus countless variations.
@Jon Busby: there will not be a "premium" edition in case you are worried about a close source commercial edition. The purpose of the editions is to convey the idea that you can have many versions of the framework.

For example there could be a "Rest Server Edition" or a "CMF Edition" that come preconfigured with relevant Bundles, libs and settings.
Namespaced annotations,
Less wtf's..

Awesome idea =)
Very nice feature. It would be cool if the reflection API supports a ReflectionNamespace class, to query this use statements.

Is there anyone with C and PHP internal skills, who can implement this missing feature, so that it can be merged into PHP5.4!?

Comments are closed.

To ensure that comments stay relevant, they are closed for old posts.