Bringing annotations to Yii

As description for the @var or @property declared above.

@property, @method, @return.

As I know, it was always supported for Yii models.

No. public only.

btw., in Yii persistent properties are not declared. Since ActiveRecord is used it is getting schema info automatically and there is no need to explicitly declare anything except maybe some validation rules. @property declarations generated by Gii are just for IDEs code completion.

Not sure, if that’s what you mean, but for AR you can’t use getter/setter for DB attributes. Check the source of __get(). It will always first check for a db column with that name. If the name is found in $this->_attributes it will not call parent implementation CComponent::__get() where the getter would be called.

http://www.yiiframework.com/doc/api/1.1/CActiveRecord#__get-detail

http://www.yiiframework.com/doc/api/1.1/CComponent#__get-detail

Yeah, that’s how I recalled it.

Thanks for clearing that up.

Oh, so I need to support annotations for @property, not for @var, which is just for descriptions - correct? (PHP-DOC documentation is rather messy…)

My own library supports annotations on classes, methods and properties. From what I’ve seen of practical applications for annotations, annotating arguments has a pretty limited use - mainly IOC containers. Annotating return values is almost unheard of, from what I’ve seen.

I’m willing to reconsider that position of course, if I hear a convincing argument why they’re needed.

Well, that’s the AR pattern, and it’s always been one of the most frequently heard arguments in debates about active record vs decoupled object/relational mappers.

But as you just pointed out, there is always a need to declare things, if just for documentation - after all, what good is a property if no one knows it’s there? So at the very minimum, you have to write an annotation to document it’s existence.

In practice, for most models, you have to describe each property in many other ways: how to validate it, how to label inputs, whether it’s safe for massive assignment and perhaps in which scenario, etc.

I prefer code that looks and functions like code. When there’s a code option and a documentation option, I’ll always take the code option. Hence, I would much prefer to see “public $name”, which is recognized by PHP (and programmers) and works with other PHP-features like has_property() and property reflection, as opposed to “@property $name” in a comment-block, of which PHP is entirely unaware.

Now, you could use the same argument against annotations in PHP - the difference is, annotations are not available in PHP, and properties are :wink: … if we want annotations now, we’ll have to get our hands dirty. (and the contributed PHP annotation extension does NOT look promising…)

As I know, @var is valid too but is generally used for inline variables, not class members. As for @return, I’ve just telling which annotations are used commonly.

Well, if your annotations approach will be really dry and performance hit will be insignificant, I think it will be a good optional addition to AR.

Sure, it’s not meant as a replacement. For most tasks, this will probably be faster, easier and more legible - that’s my hope, anyway. For certain specialized tasks, say, if the description or input on a form is generated dynamically, static metadata won’t work.

(although I suspect this is already impossible with AR in Yii, as the methods that provide various property metadata are invoked only once per request, for a single static instance of any given AR model object? if I recall, at least the validation rules are only constructed once, as an optimization, not for every instance - meaning the validation rules and other property metadata do not actually provide variability to begin with…?)

Do you know if PHP-DOC parsers will ignore PHP-DOC-like annotations they don’t recognize?

So for example, could we change the syntax to something like this:




class User extends GActiveRecord

{

  /**

   * @PrimaryKey()

   * @property integer $id

   *

   * @Length(255)

   * @Type('email')

   * @property string $email


...



I guess individual implementations of PHP-DOC parsers in documentation generators and IDEs might react differently to unknown tags like these?

Depends on the parser.

btw., just found this one: http://www.doctrine-project.org/projects/common/2.0/docs/reference/annotations/en#annotations

Yep, I believe this is what the new version of Symfony uses?

I guess if they can get away with this sort of extended PHP-DOC syntax, so can I? :wink:

Yes, Doctrine is now the main Symfony ORM.

Sure you can ;)

I wonder how it would react to multi-line annotations though. I can’t imagine that’s going to go well, since PHP-DOC does not have any existing multi-line annotations or any syntax expecting that… :-/

Well, you can try this yourself:

PhpStorm: http://confluence.jetbrains.net/display/WI/Web+IDE+EAP

NetBeans: http://netbeans.org/downloads/

If anyone’s still listening on this thread, here’s an update.

My annotation library is still in development - after months of thought and discussion with other developers, I finally have satisfying solutions to the remaining conceptual problems, some of which are implemented, and some of which will require another couple of weekends of hard work.

Annotations seem to be making their way into many other PHP frameworks by now. Are annotations still not on the chart for Yii 2.0? Just wondering.

If Yii were to support annotations, I would be glad to contribute this library when it’s complete.

Right now annotations aren’t planned for Yii2 but since Yii2 is too far from public release everything can change.

makes sense: annotations for routes

Just a quick note to let you know, I have been working hard on this project - here’s what I’ve been up to in the last couple of months:

  • Refactored the codebase to use namespaces, and the library itself now supports namespaced annotations. (to me, personally, I find this feature has very little practical use, but a couple of important people in the community were adamant about this)

  • Added a demo-script showing (with step-by-step instructions) how to consume source code annotations and use them to drive user interface, type-conversion, validation, etc.

  • The AnnotationManager now has a registry, allowing you to decouple the implementation of an annotation from the application of an annotation to a source-code element.

  • Documentation is nearly complete, although still with a few things missing here and there.

The Wiki is a good place to start.

A few of the standard annotations are in place too - enough to drive the demo script.

One problem remains and needs to be addressed before version 1.0 of my annotation engine - and before I start integrating this with Yii, which is my eventual goal. I was wondering if any of you might have some ideas?

Take the following example:




class Foo

{

  private $values = array(

    'bar' => 'hello',

    // ...

  );


  public function __get($name)

  {

    return $this->values[$name];

  }

}



How do you annotate the virtual member $bar ?

I thought I had addressed this problem, and the current implementation does provide a working solution, but I’ve decided I’m still not satisfied with this. It’s currently solved as follows:




/**

 * @required

 * @property $bar

 *

 * @table('name'=>'items')

 */

class Test

{

  // ...

}



In this example, the @required annotation is applied to the virtual member $bar, because the @property annotation implements a "delegation" interface… annotations can delegate annotations to a virtual member property/method in this way.

Because the @required annotation precedes the @property annotation, it gets delegated to the virtual $bar member.

The extra space means nothing, it’s just there for clarity - any annotations following the @property annotation go where they normally would, in this case to the Test class.

This feature works and does solve the problem, but there is no visible syntax when you apply this feature, and this is where I see a problem.

I think I should add some kind of syntax that makes it clear which annotations get delegated - I have a feeling too many people are otherwise going to have to learn the hard way why annotations seem to "disappear" when using @var and @property etc…

I thought it might look like this:




/**

 * @table('name'=>'items')

 *

 * @property $bar

 * @@required

 */

class Test

{

  // ...

}



It looks a bit odd, I guess - but it’s at least obvious that something is different here :wink:

Perhaps better would be:




/**

 * @table('name'=>'items')

 *

 * @property $bar {

 *   @required

 * }

 */

class Test

{

  // ...

}



Looks a bit odd too, I guess - and could collide (at least visually) with curly braces, if some annotation takes an anonymous function (closure) as argument.

Any thoughts? ideas?


/**

 * @required

 * @property $bar

 *

 * @table('name'=>'items')

 */

class Test

{



this can be easily confused with annotating a class with @required, especially at a glance view, when annotating the class makes sense

writing an anonymous function within phpdoc-comments is not a good idea, it doesn’t make big sense even if annotations is a part of language… I think so

The last variant is the most safe and understandable

I agree.

Unfortunately, it’s not compatible with PHP-DOC - documentation generators and IDEs are going to interpret that last bracket and following line of annotation as being part of the comments for the first annotation.

I’ve contacted the PHP-DOC developers to see if they would be interested in adding support for this to the PHP-DOC standard in some form. I can’t think of any other real way around this problem…

Okay, I contacted the PHP-DOC developers, and they said I was welcome to contribute a patch.

I took a look at their parser, and unfortunately, there’s no way I can dedicate the amount of time it would take to find my way around this mother of a codebase.

I wonder if I would be better off adding a syntax like the first one, or dropping the annotation of virtual members altogether. It feels weird to me in the first place, and if Yii no longer needs it, maybe it would be better not to have this feature, as opposed to having to explain how it works and why it’s there?

If virtual members aren’t really needed for AR anymore, and can be declared as regular public members, perhaps that’s the best approach.

I realize virtual members are a part of the PHP language, but come to think of it, virtual members are part of most other languages, and I’ve never seen annotation of virtual members supported anywhere else.

Do you think it would be acceptable to drop this feature, at least from the 1.0 branch, so I can get this thing to release this century? :slight_smile:

Any opinions?