I wrote an annotation framework for PHP - I’ve been refining and testing over the past few months, and I’m pondering the next logical step for integration with Yii.
The main thing I need to address, is a practical approach for the syntax.
The problem is, the active record implementation in Yii uses virtual properties for persistence. Meaning, when you look at the source code of a CActiveRecord class, you see something like this:
class User extends GActiveRecord
{
/**
* @var integer $id
* @var string $email
* @var string $firstname
* @var string $lastname
...
In other words, the persistent properties aren’t actually declared as PHP code - they’re evaluated at run-time, and don’t actually exist as PHP class members.
The trouble with that (in relation to annotations in PHP) is, most annotation frameworks rely on reflection to find the annotation mark-up.
In my own solution, I opted for a simple parser that actually scans the PHP code for the annotations, as this gives me more freedom in terms of syntax - I make minimal use of reflection, only as a means of finding the source code file associated with a class being inspected for annotations.
So that’s the good news, but one complication remains: how do you annotate properties that do not exist?
For a plain old PHP object, my annotation library uses the following syntax:
class User
{
#[PrimaryKey()]
public $id;
#[Length(255)]
#[Type('email')]
public $email;
...
}
Unlike most other annotation layers for PHP, my implementation does not use PHP-DOC syntax for the annotations - I opted for a syntax that that is shorter and more similar to existing PHP syntax.
I would like to stand by that choice. I really don’t like the idea of mixing documentation syntax with functionality syntax.
However, there is of course the IDE aspect to consider - and all modern PHP IDEs rely on PHP-DOC syntax for declarations like those seen in CActiveRecord classes to inform them about existing virtual properties.
In other words, there’s really no way around them.
And since declaring the property names that way is already a well-established convention, I need to make a difficult choice.
-
Get rid of my existing syntax and change it to something PHP-DOC compatible. In which case my project becomes a lot more similar to other existing annotation libraries for PHP.
-
Extend my syntax to allow annotation of virtual members. It could look something like this:
class User extends GActiveRecord
{
/**
* [PrimaryKey()]
* @var integer $id
*
* [Length(255)]
* [Type('email')]
* @var string $email
...
The two syntaxes aren’t difficult to mix as such. I wonder how existing PHP-DOC parsers will interpret my annotations though?
My main concern with the second approach, blending with PHP-DOC syntax, is whether this will escalate - will there be other types of PHP-DOC annotations I’ll need to take into account besides @var?
There is another, perhaps more serious problem, with the first approach though - how do you apply annotations to members (properties) which themselves only exist in the form of an @var annotation?
I poked around to see how other annotation frameworks address this issue - Addendum, for one, does not seem to address it. Some frameworks support nested annotations, but that in my opinion adds another degree of complexity and messy syntax - and PHP-DOC syntax does not include nested annotations in the first place, so the syntax would be a superset of PHP-DOC under any circumstances.
Looking for any kind of ideas and input here.
I would like to take this library and actually apply it in practice. My first goal is to write a CActiveRecord extension that implements a number of the configuration callbacks: attributeNames(), attributeLabels(), tableName(), primaryKey(), rules(), etc. - with annotations to handle all of the standard CActiveRecord configuration and eliminate the redundant methods and repeated property names as array keys in each of those.
Once that is done, I would release this as an extension.
But first I need to make some hard decisions here, and after months of pondering and going back and forth on the subject, I need help!
Thanks for reading this lengthy post!