tl;dr: Code comments should never have an effect on application functionality or flow.

UPDATE: It has come to my attention that there is an RFC pending that would add an annotation syntax to PHP (link). I fully support making annotations a language feature. This post specifically criticizes the current implementation of annotations in code comments.

Both the Symfony 2 and Doctrine 2 libraries and components make liberal use of what have come to be called annotations—special code comments, usually prefixed with an @ that are actually interpreted by the application and affect its functionality. For example, in order to use PHP templates for a controller action with Symfony, one must declare that the returned value should be rendered with a template in the following way:

/**
 * @Template(engine="php")
 */
public function indexAction()
{
    ...  
}

Without the special @Template comment, Symfony does not know where to find the template file.

Doctrine 2 does the same thing when declaring object properties based on database table columns1:

/**
 * @Column(type="string", length=32, unique=true, nullable=false)
 */
protected $username;

This trend needs to die.

Why?

Because code comments should never be necessary for a script to function properly. Code comments are exactly that—comments. Their purpose is to provide commentary on the code, not to provide logic that is critical to the application’s functionality.

1. DX Regressions

Consider debugging code in which several different types of critical application logic are contained within annotations. There are several DX regressions:

  • You can’t use any of PHP’s helpful linting capabilities (php -l).
  • Try to var_dump() or debug_backtrace() an annotation. You simply can’t.
  • Your IDE can’t link to classes in which an annotation is defined.
  • Sometimes, developers set their editors (like vim) to automatically fold comments in order to save screen space. In this case, they may never actually see the annotations that are making your code work.

2. Decreased Readability/Discoverability

A developer who knows PHP very well can spend a couple hours with most applications and frameworks, and figure out the basics. If you can read PHP, and the code is not unreasonable obtuse, you should be up and running pretty quickly. However, annotations do not necessarily make sense to a developer who knows PHP perfectly well, because they are not native to the language. Based on their knowledge of code comments (that, usually, they do not affect the application logic), they would not immediately know to look there when debugging.

3. Reliance on Yet Another Library

If you use annotations, your application is now dependant on a library that parses annotations (doctrine/common, most likely). I’m sure quite a number of development hours were/are spent writing and bugfixing that library, all of which could have been spent on other projects.

4. Icky Feeling

Perhaps it’s just me, but it just feels wrong to put application logic inside comments. They’re a bit magical, which does not lend itself to writing maintainable code.

Alternatives

But most of all, annotations really signal to me a lack of functionality or flexibility in PHP itself—the PHP community is now officially so desperate for better metaprogramming capabilities that it is attempting to do so using code comments.

With a language like Ruby, which allows for class-level function calls, you do not need annotations because you can define configuration in a declarative way, like so:

class BlogPost < ActiveRecord::Base
  attr_accessible :name, :body
end

The fact that the language permits you to call functions within a class, but outside of a function definition, allows for extremely elegant configuration. Though I don’t know much about the inner-workings of the Ruby language, I’m sure this has something to do with the fact that Ruby classes can be reopened throughout the compilation lifecycle.

However, it seems like there are equally elegant ways to achieve the same result with PHP using class properties. Consider:

class User
{
    public static $mapping = [
        'username' => [ 'type' => 'string', 'length' => 32, 'unique' => true ]
    ];
}

Then Doctrine could grab all of the $mapping properties from model classes, and wrap them in a nice configuration class so that we don’t have to deal with dumb arrays later in the lifecycle. And now that PHP has proper lambda functions and closures, you can even make your definition a bit more dynamic, as shown above, should the need arise.

Concluding

So annotations suck for a variety of reasons. With PHP, we have elegant alternatives. My vote is that we stop using them, and remove the ability to use them from frameworks and libraries. If you have compelling reasons for using annotations, I would love to know what they are.

  1. Fortunately, Doctrine also allows you to declare property metadata using PHP, YAML, or XML, though none of the options is particularly elegant.