PHP Annotations are a Bad Idea

By | October 25, 2013

I’ve been writing code in PHP for a long time now, both for my own projects and as a freelancer.  I’ve seen well written code and truly horrific code and everything in between.  Much of the work I’ve done for my personal projects has been using a framework that I’ve built and added on over the years, my PHP Foundation Classes.

Lately, however, I’ve found the need to use a more generic framework and have evaluated Yii, Symfony2, CakePHP, CodeIgniter and of course the Zend Framework.

After examining them all, I narrowed down my focus to Yii and Symfony2. I really like Symfony2 because it integrates well with the Doctrine ORM. I’ve used Doctrine v1 extensively in other projects and it is fantastic. This would make Symfony2 an obvious choice for me, but there is one thing about it that I just can’t get past: Annotations. Annotations in Symfony2 and Doctrine2 are what are keeping me from using it.

Annotations are specially formatted entries in the comments of a source file that control its runtime behavior. Comments should never have any impact on code behavior. Ever.

Now, Symfony2 and Doctrine2 can also be configured and controlled via XML or YAML files, but since they’re not as “convenient” they’re not used nearly as much as annotations in the core library or the third party modules.

Annotations are great for things like auto generating documentation, but shouldn’t be used for code control.

For certain projects, I also use SourceGuardian to encode and license my projects. Annotations by their definition are incompatible since SourceGuardian strips comments as part of its encoding process.

Yii has a very clean solution that accomplishes the same thing that Annotations do. The main.php configuration file. Using arrays to configure the application is extremely fast and clear. To change a route or URL I don’t have to search for YAML, XML or source files, I just go to the main.php and edit it. Centrally located, fast, and convenient.

I still love Doctrine v1. I use it in several projects and it integrates nicely with both Yii and my own foundation classes.

30 thoughts on “PHP Annotations are a Bad Idea

  1. Hmm

    Most frameworks use annotation for the sake of configuration only. Annotations, xml, yaml… it is a matter of taste.

    Reply
  2. Loïc Chardonnet

    Hi Marc,

    Please keep in mind that the annotations you’re talking about are only configurations (not comments) and are “compiled” later into PHP.

    They’re only written in comments because PHP does not support them natively (unlike Python for example), so technically they aren’t comments that “have any impact on the code behavior”.

    Also Symfony2 allows you to use not only annotations, XML and YAML for your configuration, but also PHP (in which the other formats are compiled to anyway).

    Cheers,
    Loïc

    Reply
  3. marc Post author

    Greetings Loïc,

    That was kind of my point, actually. They’re configurations, but since PHP only supports them through third party add-ons they are in comments. Using Symofny2 as an example, my opinion is that something that is designed for enterprise use, shouldn’t be using a hack like this.

    The “compiling” happens at runtime. If a project has been encoded using something like SourceGuardian, there are no comments left to examine for annotations.

    The fact that Symfony2 also allows XML and YAML and direct PHP configurations are great. But does a framework really need four different methods for configuration? I know choice is great, but having four different control methods is confusing. Going through the tutorials and having to click on different “YAML” or “XML” tabs is great, but most of them still showed annotations as the default and sometimes the only option (at least when I went through them last).

    As I said in my original post, its the most convenient, so its likely going to get used the most.

    Since they’re in comments, though, they’re a bad idea. I would never use annotations in any of my projects for anything except code documentation.

    Reply
  4. Annabelle K. Mcgowan

    They are a very useful tool for documenting code. However, they should not be abused to configure an application. Each of the seven points I made above is enough on its own to warrant avoiding using annotations for storing application metadata. The fact there are seven real world problems (likely more, I probably missed some obvious ones!) introduced by their use makes them totally unfit for any purpose. This is one of the few cases where I’d even go as far as saying: They should never be used. With a lot of bad practices, there are certain scenarios where they can add some benefit, usually because they’re a shortcut and make development time significantly faster (even if they introduce problems in the future) or avoid a lot of complexity so make sense for small projects. However, annotations add complexity and don’t offer enough of a benefit at all to warrant any use. The single benefit is that it allows programmers to edit two sets of data (application logic and application configuration) within a single file. Compared with the problems they cause this is not enough to ever encourage their use.

    Reply
  5. Joe Robles

    Hi Marc,

    You are confusing the term “comment ” with “annotation” them are totally different.

    Comments are written in human nature language, are significant and recommended to help understand other developers about an specific part of code, and are ignored by complires and interpreters.

    Annotations are written following a syntax, are significant metadata required to control code behavior, so, are not ignored by by compliers and interpreters of the programming language or thirds.

    And differ in their syntax:

    PHP single line comments:
    //single line comment

    PHP multiple line comments:
    /*
    this is a
    multiple line
    comment
    */

    PHP annotations:
    /**
    * Calculate a stock price for a given ticker symbol.
    *
    * @Route(“/”, name=”cliente”)
    * @Method(“GET”)
    * @ORMGeneratedValue(strategy=”AUTO”)
    */

    Greetings.

    Reply
  6. marc Post author

    You are correct from the perspective of human semantics.

    PHP annotations are in comment blocks, so therefore from a programming language perspective, they are a comment. Yes, they do require specific formatting for the annotation parser to pull them out, but they are still comments that control program flow, which is terrible from a design perspective.

    Perhaps I’m a bit of a purist in this regard, but if I install a library, plugin, or module to use within an application I’m writing, I should not have to modify the library code to change a configurable behavior. This should be done in a centralized configuration location, not chasing down annotations that may be buried in code. Having to pour through library code to chase down a bug or change a configuration is a huge waste of time and resources.

    A centralized configuration, such as Yii’s protected/config/main.php, or even Symfony 1.4’s app/config directory is much, much cleaner.

    One of my CS instructors said something in a lecture that has resonated with me for nearly 25 years now: “Always choose clear code over clever code.” Annotations muddy things up badly and make things less clear.

    Reply
    1. c40s

      Marc,

      Comments are not the same as a Doc-Block. If you look at the AST you’ll notice that there’s a different token for each one. That’s because the interpreter makes a simple distinction: Doc-Blocks make it to the op-code, comments do not. So your logic is flawed in saying “They’re configurations, but since PHP only supports them through third party add-ons they are in comments” is a false cause logical fallacy. And your over-all argument against annotations falls under the no true Scotsman fallacy. The only logical reason you have to reject annotations is your opinion. As you have provided no real reason why they are bad.

      P.S. Creating your own framework is one of the worst things you can do when doing programming in a team environment. I think it’s a great thing for programmers learning how patterns work, etc…but there are a few reasons frameworks like SF2 and Zend dominate the PHP marketplace: Documentation, No maintenance of boilerplate code.

      When you create your own framework (unless you are specifically encrypting that application and work exclusively on your own) you will ALWAYS have increased ramp-up time as no developer has ever worked with this API before and more than likely it has very limited (if any) documentation. The act of maintaining it makes any excuse about not learning a dominant framework invalid; to add features you’ll have to add/modify code in your custom framework/library which does not translate into billable hours, so that’s time you could have spent making yourself marketable (by learning that framework that someone else is maintaining for you).

      Reply
  7. truth

    I could not agree more Marc. Nowhere is this more frustrating than when beginning with Symfony2 and Doctrine. You realize you need to learn a whole new secret syntax (with rules, parameters, etc.) on top of the PHP.

    If these ‘configurations’ are so important then why not written directly into the code. Why isn’t it added to PHP? Because it creates very brittle coupling, that’s why.

    Reply
  8. piotrek

    1. You dont have to learn new syntax – each annotation is well documented
    2. You can write your own annotation parsers/handlers (it is super cool to set up an annotation like @Guard(userRole=”ADMIN”) to fire up before every method that it’s tied to, to check whether user has enough permission to perform this action).
    3. Annotation are parsed and compiled to PHP and kept as cache, so they are used ONLY once since parsing them is time-consuming.
    4. You can use annotation to configure one little thing, and use YAML/XML/PHP Array to configure things that occure very often in your code.
    5. Annotations saves time and space. For example check symfony controllers, youc can your annotations like @METHOD, @ROUTE, @TEMPLATE to save space inside controller

    … and many many more advantages…

    Reply
    1. Garry Boddard

      @piotrek

      “You dont have to learn new syntax – each annotation is well documented”

      Swahili is well documented. Do you claim you’d be be able to speak it without learning it?

      Reply
  9. Marc Post author

    1 and 2. They’re still inside of a comment block. Yes, its a sticking point with me, but its still a comment. Instead of using a comment block, why not replace them with something similar such as, within the method (this isn’t real code, just pseudo code I’m making up as I write this), as an example:

    Where you have:

    /**
    * @Guard(userRole="ADMIN")
    */
    public function doSomething()
    {
    ...
    }

    You could/SHOULD have instead written this as:
    /**
    * doSomething() - This member does something.
    */
    public function doSomething()
    {
    App::guard()->setUserRole("ADMIN");
    }

    How are annotations making that any more clear? Using the second method its more clear, or even more clear still, in a configuration file (using a Yii like configuration file example).

    $config = array(
    ...
    'modules' => array(
    'doingSomething' => array(
    'guard' => array(
    'userRole' = 'ADMIN',
    );
    );
    );
    );

    Now this config file example is very clear and I don’t have to edit any code to change its configuration. Yes, it takes a bit more thought in the framework, but from the end programmer’s perspective, I know that *all* of my configurations are in one place. If I want to change the default behavior of something, I can go change ‘userRole’ = ‘ADMIN’ to ‘userRole’ = ‘MEMBER’. I do not have to go hunting through possibly dozens of source files and their associated comment blocks to change this configurable value.

    3. They’re parsed, not compiled. PHP is an interpreted language. And this type of behavior also adds additional file checking overhead. Granted, with today’s systems its minimal to check the mtime of a file and then compare it against the pre-parsed cache, but its still one extra step and additional overhead. It also renders any file that uses annotations incompatible with tools like SourceGuardian if I want to protect or sell my code and not have it exposed.

    Also, its not actually cached. Its parsed and PHP code is generated which is then referenced by the controller. Its cached in the sense that its not regenerated each time the code is called. It is, however checked each time against the source file to make sure that the source hasn’t been changed and things need to be generated again. Tools like Xcache or APC will actually handle the caching.

    4. Thats bad form. A well designed and thought out application should have one, and just one method of configuring it. It shouldn’t be guess work as to which of the four different methods was used to configure this behavior.

    5. Saving typed space is the last thing on my mind when I’m writing code (I do use Xcache or APC on every deployment also). Using annotations actually generates additional code that needs to be processed by the PHP interpreter from the generated “cached” code, thereby making the program more complex and resource intensive. It saves the programmer a few keystrokes, but does not save space.

    So, I’m still not convinced, nor do I think I will be. I know there is an RFC to implement annotations, and personally, I’m against it. There are already dozens of other ways to accomplish the same thing that doesn’t rely on comments that control application behavior.

    Reply
    1. Wirone

      1. Annotations have own handlers so you can use annotations in your code multiple times and when you have to fix some behavior, you have to change it only once in annotation’s handler. When you put some code into methods (like App::guard()->setUserRole(“ADMIN”);) there is a risk you will have to review your code and change multiple times the same thing (DRY).

      3. AFAIK Symfony checks for changes only in dev environment and updates configuration dynamically. In prod you will get fatal error when, for example, new service was added and used in code, but it isn’t in cache. You have to explicitely clear cache for prod when deploying new version.

      4. I don’t agree. Well designed application should provide flexibility and offer end users best way for THEM to use it. If they want annotations, they can use it. If they prefer XML – fine, there’s XmlFileLoader etc.

      Additionally – annotations can be reused easily, without extracting some parts of code from one method to another or one project to another (ok – always some code has to be copied, but with annotations it’s – imho – more simple). Multiple bundles can make use from same annotations (like NelmioApiDocBundle use annotations from FOSRestBundle).

      Annotations are not ideal and – fortunately – not required. It’s up to developers if they want to use it. One will find them useful, other won’t. And that’s cool 😉

      Reply
    1. Marc Post author

      I do. And I use portions of the Symfony project, depending on what I’m working on. For example, Twig and Doctrine both work very nicely with Yii. Its typically not a one thing or the other with me. I generally try to use the most appropriate tools for the job.

      “Best” is highly subjective.

      Reply
    1. Wirone

      “To use Symphony routing as an example, there’s no way to get an overview of all the routes used by the application”

      app/console debug:router

      “For instance, what if I wanted to restructure all the urls so that everything that was in /users/…/…/ becomes /customers/…/… if the configuration of those is spread amongst a dozen files that becomes a dozen files to locate then edit.”

      It is not annotation-related case, because YAML files with routing also can be spreaded. There’s possibility to import routing resource (like bundle’s routing) with prefix, so it is only matter of proper usage and configuration. You can even place @Route annotation on class level to set prefix for all action’s routes and change it to new when you want, without touching “sub-resources”.

      I stop reading there, because I think that guy didn’t even get along with Symfony properly and is blaming annotations for his unawareness of framework’s functionalities.

      I understand arguments about mixing code control with comments, but still… Annotations are time savers for those who want to use it and nobody is forcing anybody to use them too.

      Reply
  10. pine3ree

    I concur on the fact that annotations are a bad programming practice.

    Commented lines should not be part of the code but only reference to the developer and documentation builder tools. Code should work with all comments stripped out.

    I see every major and moder project talking about SRP and popo/pojo enties and then you find annotations inside them. If an object should not know about persistence, then it should not know about persistence configuration as well.

    Nevertheless i use zf2+doctrine2, sf2+doctrine2, java hibernate….i just avoid annotations and use real configuration files, yaml if available.

    Reply
    1. Garry Boddard

      “Code should work with all comments stripped out.”

      Why? Do you strip comments out before you run your code?

      Reply
      1. pine3ree

        Why?? because a comment is a comment by definition.
        The purpose of a comment block is not to be part of the code, otherwise it would be simply another code block.

        I like doc-blocks and i like ide code hinting bases on comments, but…

        Annotations is just code inside comment blocks.

        I don’t blame anyone using it as a programming shortcut. But classes containing annotations are not to be considered popo objects anymore, because they know and need to know or need to make some other class know about something that could ber related to persistence, etc… something that is not the object’s responsibility.

        …and yes…sometimes for performance purposes i combine many (always used) classes together into a single class cache file stripping out comments.

        Reply
        1. presto

          Do any of you know about something called ‘autoload’?

          What does it do? Basically (and roughly) require all files from your project into one big file. From that to strip out all comments for performance sake is not a far jump.

          As if PHP wasn’t bad enough, now we’re going to use comments as control structures?

          When the next ‘PHP is a Fractal of Bad Design’ goes out, there will be another sh*tstorm about ‘how fallacious’ and ‘wrong’ the said post is, but we will still be happy using comments as control structures.

          Reply
  11. Pingback: Why PHP is obsolete | Smash Company

  12. Dino

    Wow. This entire gripe session is just grandstanding and full of misconceptions.Y’all are rookies!

    Annotations are optional. XML is optional. YAML is optional. You just have to pick one. It doesn’t hurt. Annotations just sit there doing nothing if you choose YAML. Who cares?

    Just state your frickin’ preference and get on with coding. Then we can start a real flame war – which goes better when the choice is narrowed down to two.

    XML sucks because it’s so verbose.

    Yeah? Well YAML has no validation or namespaces. It’s for amateurs.

    XML and YAML both suck because you have to open a separate file in order to configure my route/model/controller – annotations rule!

    We aren’t talking about annotations anymore, fool!

    Choice is good. Pasta shells or spaghetti? You chose to dump your homemade framework for something better.

    Instead of being thankful for the diversity you criticize something you don’t fully understand or appreciate. Sad.

    Reply
  13. Dino

    This post is just grandstanding. Anyone griping about Annotations sounds like a rookie.

    Read this thread for an objective, emotion-free take on Annotations.

    https://groups.google.com/forum/#!topic/symfony2/xnzEIOSvv64

    Annotations, YAML, XML – these are your configuration options. Annotations are not required – until you choose to use it. You can even choose to use them in routing. Or not. Or choose YAML for ORM, Annotations for routing and YAML for everything else. Or change your mind. Annotations are in comment blocks so are harmless if you decide to use YAML instead.

    Choice is good. Pasta shells or spaghetti? Marc, you chose wisely to put down the homespun framework and choose something better – whether it’s Yii or Symfony or Laravel, it’s most certainly better than what you made. No offense, I traveled that road too, and thankfully I’m using Symfony now.

    Try Annotations. Give them a good chance. You probably won’t go back to YAML – seriously!

    Reply
  14. Dino

    ack!! sorry for the “double” post. 1st didn’t seem like it went through (and wish it hadn’t 🙂

    Reply
    1. pine3ree

      Hello, it happens… 🙂

      anyway i don’t think it’s some kind of religious fight, we all are just exchanging opinions and learning from different points of view.

      About optional choices i respectfully don’t agree about Annotations.

      I think it’s a cool feature, but not a good practice.

      consider annotations in the model layer.

      If i define my entities using xml, yaml configuratons, those files will be needed and parsed by the orm, whose responsibility is to map an object to a persistence layer.

      Annotations have the same purpose but are “hidden” in comment blocks inside the entity class.

      It’s my opinion in order to justify annotation usage the php community will need to establish that those particular comment blocks are part of the language.

      if they become part of the language, then your entities will have “legal” persistence information inside the classes defining them. This will break the SRP and we would not call them POPO objects anymore. I’ll even be prefering AR (and there are good ones around) to this. :-). But that’s just me.

      kind regards

      Reply
  15. Kyle Harrison (@RedactedProfile)

    I.. honestly don’t know where the concept of “Annotations are Default” came from?

    Anytime you visit the documentation, YAML is the majority of the default chosen tab in the selectors. Also when you use the console tools to generate bundles and other such things, the default option when you keep slamming the Enter key without additional input is always YAML.

    The only exception I’ve found is with Doctrine2 entities. Annotations is the default there. But you can choose any other method of configuration, obviously including YAML (as you’ve stated). I find the Annotations when it comes to Doctrine2 handling to be the best though thanks to 3rd party doctrine enhancements (Like Gedmo) that can be very difficult or almost impossible to implement in a serialized configuration file like YAML or XML.

    Though, full disclosure: I’ve been using Symfony since 2.2, maybe your talking about a version I hadn’t used?

    Reply
    1. pine3ree

      Hello Kyle,

      i always used YamlDriver for Doctrine entities.

      Since symfony 1.x (I started with 1.2) configuration was yaml based, so for consistency i always tried to use yaml for everything.

      But the point is not the fact that Annotations are not useful, or that you don’t have to use it.

      I am merely stating that Annotations lines ARE code~configuration lines not mere suggestions or simple comments you can cut out.

      Since in Doctrine this configuration is inside a entity class definition and is essential to define db persistence, you cannot call your entities POPObjects

      In my opinion only the ORM layer should the one being aware of the persistence implementation, not the entities. So i think that using yaml is a better programming practice.

      One of the point of doctrine – quoting Ocramius – is “Forget about the database”.

      You just use simple entities and the relation between each other. You implement the relations using Collection or properties representing related entities in the entity classes and adding methods that modify these relations. The ORM translates the state of these objects’ relations into database tables relations when you call “flush”.

      If you want to forget about the database then entites should do that as well. So why should a entity class contain foreign keys, columns, db table information, etc…?

      If an entity data is mainly retrieved from a remote service and could occasionally be stored in a local database, should we define both db persistance and remote persistance information as Annotation code inside it class?
      An what if the entity could be also stored somewhere else? Should we add the information about how this storage works using more Annotation code as well?

      wouldn’t it be a little messy.?

      shouldn’t we avoid having configuration inside class definitions?

      I believe that how some service stores an entity should be available to that service only. The remote service manager knows how to retrieve/save remotely, Doctrine knows how to save to a db and some other persistence service knows its stuff. To each one its own….

      To me using annotations in doctrine is pretending the the entities do not contain information about the database – as they should – while they actually do in a hidden way.

      Luckily it’s a developer’s choice….so anyone can choose to use or not to use it.
      I don’t.

      kindly…

      Reply
  16. Pingback: Your Programming Language Sucks - Vegibit

Leave a Reply

Your email address will not be published. Required fields are marked *