On Thu, Apr 21, 2016 at 11:52 PM, Larry Garfield <la...@garfieldtech.com>
wrote:

> On 4/21/16 4:13 PM, Dmitry Stogov wrote:
>
>> Hi,
>>
>>
>> I would like to present an RFC proposing support for native annotation.
>>
>> The naming, syntax and behavior are mostly influenced by HHVM Hack, but
>> not exactly the same.
>>
>> The most interesting difference is an ability to use arbitrary PHP
>> expressions as attribute values.
>>
>> These expressions are not evaluated, but stored as Abstract Syntax Trees,
>> and later may be accessed (node by node) in PHP extensions, preprocessors
>> and PHP scripts their selves. I think this ability may be useful for
>> "Design By Contract", other formal verification systems, Aspect Oriented
>> Programming, etc
>>
>>
>> https://wiki.php.net/rfc/attributes
>>
>>
>> Note that this approach is going to be native, in contrast to doc-comment
>> approach that uses not well defined syntax, and even not parsed by PHP
>> itself.
>>
>>
>> Additional ideas, endorsement and criticism are welcome.
>>
>>
>> Thanks. Dmitry.
>>
>
> Thanks, Dmitry!  In concept I am in favor of syntax-native annotations,
> although I have some concerns with the specifics of the proposal.  Thoughts
> in no particular order:
>
> First, for the getAttributes() reflection method, please oh please don't
> return array-or-false.  That's horrible.  Just return an empty array if
> there aren't any, as that makes getAttributes() entirely type safe and
> saves all callers from a mandatory if-check.  (See
> http://www.garfieldtech.com/blog/empty-return-values for more
> information.)
>
> The reflection section further indicates that the type of the result is
> variable, which means I cannot know in advance if I'm going to get back a
> scalar or an array.  If we go with this free-form approach, I'd honestly
> prefer to always get back an array, even for single value, so that I can
> always know the type I'm dealing with. (Since I cannot enforce a given
> attribute to be single-value.)
>
> For the expression example:
>
> <<test($a  +  $b   >  0)>>
> function  foo($a,  $b)  {
> }
>
>
> It is not at all clear to me what scope the annotation's $a and $b exist
> in.  Are the they same $a and $b as in the function signature? If so, what
> happens if I reflect the function before ever calling it?  How can I
> evaluate test?  Or are they inherited from the global scope at the time of
> declaration?  (That scares me a great deal.)  I don't know what to make of
> that at all.
>

They don't exist in any scope. You get an AST of this expression, what you
do with it is entirely your choosing and you can set the scope/context
yourself.

>
> In the "Attribute syntax" section, the text says the tokens are the left
> and right double-angle character, as used for quotations in some European
> languages.  The rest of the text says it's two left/right carrot
> characters, as seen above the comma and period on US keyboards.  I'm
> assuming the former is just a typo/auto-correct bug.
>
> If I read correctly, the following two would be semantically identical:
>
> <<One, Two>>
> function foo() {}
>
> <<One>>
> <<Two>>
> function foo() {}
>
> Is there a reason you chose the name "attribute" rather than
> "annotations", which seems at least in PHP to be the more common term for
> this type of declaration?
>
> It appears that the annotations themselves are entirely free-form. At the
> risk of expanding the typing debate, this concerns me as then all we're
> adding is a new way to parse undocumented, undefined anonymous structs.
> How can I say what annotations mean what for my ORM, or routing system, or
> whatever?  We're back to, essentially, out-of-band documentation of big
> anonymous structs (aka associative arrays).
>
> A more robust alternative would be something along the same lines that
> Doctrine uses: Make annotations actual classes.  To wit:
>
>
> <<AThing>>
> <<AnotherThing('stuff')>>
> <<MoreThing(1, 2, 3)>>
> function foo($a, $b) { }


> Where AThing, AnotherThing, and MoreThing are defined classes, and subject
> to namespaces and use statements.  Then what gets returned from
> getAttributes() is an array consisting of an instance of AThing, an
> instance of AnotherThing, and an instance of MoreThing. In this example
> we'd just call their constructors with the listed values and let them do as
> they will.  Doctrine uses named properties in the annotation that maps to
> properties on the object, which is even more flexible and self-documenting
> although I don't know how feasible that is without opening up the named
> properties can of worms globally.
>

I like that its just arrays, PHP is not exclusively OOP, so making this an
OOP feature doesn't make sense to me.

A library like Doctrine can always add the meaning on top, for example
checking:

<<ORM\Entity>>
class User
{
}

Again resolving this against namespaces for example inside Doctrine
Annotations itself, like its done right now.


>
> Either way, the advantage then is that I know what annotations are
> available, and the class itself serves as documentation for what it is,
> what it does, and what its options are.  It also helps address collisions
> if two different libraries both want to use the same keyword; we already
> have a class name resolution mechanism that works and everyone is familiar
> with.


> One concern is that not all classes necessarily make sense as an
> annotation; perhaps only classes with a certain interface can be used.
> Actually (thinking aloud here), that would be a possible solution to the
> named property issue.  To wit:
>

This is why it should be just arrays, using classes suddenly tons of
special things can happen and must be thought of.


>
> <<AThing(a => 'a', b => 'b')>>
> foo() {}
>
> class AThing implements Attribute {
>   public static function attributeCreate(array $params) {
>     return new static($param['a'], $param['b']);
>   }
> }
>
> $r  = new ReflectionFunction('foo');
> $a = $r->getAttributes();
>
> $a is now an array of one element, an instance of AThing, created with 'a'
> and 'b'.  The specifics here are probably terrible, but the general idea of
> using classes to define annotations is, I think, a big step forward for
> documentation and avoiding multi-library collisions.
>
> While I know some of the things Drupal 8 is using annotations for are
> arguably excessive (and I would agree with that argument in some cases), as
> is I fear the proposed system is too free-form and rudimentary for Drupal
> to switch to them.


You can build any kind of structure on top of $refl->getAttributes() inside
your framework (Drupal in this case)

>
>
> --
> --Larry Garfield
>
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: http://www.php.net/unsub.php
>
>

Reply via email to