FAQ
Dear Internals,

I'm announcing a simplified RFC for annotations:

https://wiki.php.net/rfc/simple-annotations

It's an alternative to the proposed Attributes RFC and the (2010)
Annotations RFC.

I'm attempting with this to describe a feature that is closer to the
language than what is proposed by the Attributes RFC, by permitting
the use of any valid PHP expression as an annotation value.

Where the Attributes RFC proposes new syntax for what is essentially
arrays, this proposal instead permits you to use actual arrays, e.g.
without inventing any new syntax. It also allows you to use values of
any other type, including objects. This makes the proposed feature
more immediately useful, with a minimal learning curve.

Compared with the old Annotations RFC (and Doctrine Annotations, etc.)
this proposal does not attempt to define or enforce any rules about
what annotations are, permitted usage, inheritance rules, etc. -
instead it adds a very simple language feature upon which the
community may choose to build (and evolve) facilities that implement
additional rules and logic.

My hope is that, if we can agree on something very small and simple,
we can defer the more opinionated discussions about rules and logic to
the community.

In my opinion, language features should be simple, and consistent with
the language - I believe the way to do that, is to avoid discussions
about how such as facility should be used, and instead focus on how it
should work. There is a lot of opinion built into the old Annotations
RFC, and into Doctrine - features that attempt to dictate how the
feature should be used. I don't believe the language should dictate
what is or isn't correct or appropriate use.

Please review and comment.

Thanks,
   Rasmus Schultz

Search Discussions

  • Davey Shafik at May 13, 2016 at 12:57 pm

    On Fri, May 13, 2016 at 2:11 PM, Rasmus Schultz wrote:

    Dear Internals,

    I'm announcing a simplified RFC for annotations:

    https://wiki.php.net/rfc/simple-annotations

    It's an alternative to the proposed Attributes RFC and the (2010)
    Annotations RFC.

    I'm attempting with this to describe a feature that is closer to the
    language than what is proposed by the Attributes RFC, by permitting
    the use of any valid PHP expression as an annotation value.

    Where the Attributes RFC proposes new syntax for what is essentially
    arrays, this proposal instead permits you to use actual arrays, e.g.
    without inventing any new syntax. It also allows you to use values of
    any other type, including objects. This makes the proposed feature
    more immediately useful, with a minimal learning curve.

    Compared with the old Annotations RFC (and Doctrine Annotations, etc.)
    this proposal does not attempt to define or enforce any rules about
    what annotations are, permitted usage, inheritance rules, etc. -
    instead it adds a very simple language feature upon which the
    community may choose to build (and evolve) facilities that implement
    additional rules and logic.

    My hope is that, if we can agree on something very small and simple,
    we can defer the more opinionated discussions about rules and logic to
    the community.

    In my opinion, language features should be simple, and consistent with
    the language - I believe the way to do that, is to avoid discussions
    about how such as facility should be used, and instead focus on how it
    should work. There is a lot of opinion built into the old Annotations
    RFC, and into Doctrine - features that attempt to dictate how the
    feature should be used. I don't believe the language should dictate
    what is or isn't correct or appropriate use.

    I think I like this, however a couple of simple questions:

    1) Any chance for (optionally) _naming_ annotations? It would be nice to be
    able to do: ->getAnnotation('table') and not have to handle unnecessary
    annotations

    2) I like the idea of Hacks memoize for example, how do you see those being
    implemented? Or don't you?

    3) When are annotations executed? On ->getAnnotations()? Every time?

    Thanks,
  • Mathieu Rochette at May 13, 2016 at 1:16 pm

    On 05/13/2016 02:57 PM, Davey Shafik wrote:
    On Fri, May 13, 2016 at 2:11 PM, Rasmus Schultz wrote:

    Dear Internals,

    I'm announcing a simplified RFC for annotations:

    https://wiki.php.net/rfc/simple-annotations

    It's an alternative to the proposed Attributes RFC and the (2010)
    Annotations RFC.

    I'm attempting with this to describe a feature that is closer to the
    language than what is proposed by the Attributes RFC, by permitting
    the use of any valid PHP expression as an annotation value.

    Where the Attributes RFC proposes new syntax for what is essentially
    arrays, this proposal instead permits you to use actual arrays, e.g.
    without inventing any new syntax. It also allows you to use values of
    any other type, including objects. This makes the proposed feature
    more immediately useful, with a minimal learning curve.

    Compared with the old Annotations RFC (and Doctrine Annotations, etc.)
    this proposal does not attempt to define or enforce any rules about
    what annotations are, permitted usage, inheritance rules, etc. -
    instead it adds a very simple language feature upon which the
    community may choose to build (and evolve) facilities that implement
    additional rules and logic.

    My hope is that, if we can agree on something very small and simple,
    we can defer the more opinionated discussions about rules and logic to
    the community.

    In my opinion, language features should be simple, and consistent with
    the language - I believe the way to do that, is to avoid discussions
    about how such as facility should be used, and instead focus on how it
    should work. There is a lot of opinion built into the old Annotations
    RFC, and into Doctrine - features that attempt to dictate how the
    feature should be used. I don't believe the language should dictate
    what is or isn't correct or appropriate use.
    I think I like this, however a couple of simple questions:

    1) Any chance for (optionally) _naming_ annotations? It would be nice to be
    able to do: ->getAnnotation('table') and not have to handle unnecessary
    annotations
    not sure you need that, you can do this instead:
    ->getAnnotations(Table::class)
    however it won't throw an error if you have more than one "Table::class
    annotation" whereas I supposed you would expect so with a named annotation
    2) I like the idea of Hacks memoize for example, how do you see those being
    implemented? Or don't you?
    if Rasmus goal is to that "we can agree on something very small and
    simple" I guess it would best be left for another rfc
    3) When are annotations executed? On ->getAnnotations()? Every time?
    given they are context free, I suppose they would be executed on the
    first call only

    but what about this kind of annotation classes? :

    class Counter {
       private static $i = 0;
       private $n;
       function __construct() {
         $this->n = self::$i++;
       }
       function get() { return $this->n; }
    }

    both the getAnnotations() calls order and whether or not annotations are
    executed every time would make a difference
    Thanks,
    --
    Mathieu Rochette
  • Marco Pivetta at May 13, 2016 at 10:45 pm
    Love the simplicity of the RFC, but I can already see people doing terrible
    things with it:

      << new DateTimeImmutable() >>
    << log(get_instance('logger')) >>

    And other global-state related stuff.

    TBH, I'd rather just allow a constant array (with constant expressions
    only), and that would be good enough :-)

    Cheers,


    Marco Pivetta

    http://twitter.com/Ocramius

    http://ocramius.github.com/
    On 13 May 2016 at 15:15, Mathieu Rochette wrote:


    On 05/13/2016 02:57 PM, Davey Shafik wrote:
    On Fri, May 13, 2016 at 2:11 PM, Rasmus Schultz wrote:

    Dear Internals,

    I'm announcing a simplified RFC for annotations:

    https://wiki.php.net/rfc/simple-annotations

    It's an alternative to the proposed Attributes RFC and the (2010)
    Annotations RFC.

    I'm attempting with this to describe a feature that is closer to the
    language than what is proposed by the Attributes RFC, by permitting
    the use of any valid PHP expression as an annotation value.

    Where the Attributes RFC proposes new syntax for what is essentially
    arrays, this proposal instead permits you to use actual arrays, e.g.
    without inventing any new syntax. It also allows you to use values of
    any other type, including objects. This makes the proposed feature
    more immediately useful, with a minimal learning curve.

    Compared with the old Annotations RFC (and Doctrine Annotations, etc.)
    this proposal does not attempt to define or enforce any rules about
    what annotations are, permitted usage, inheritance rules, etc. -
    instead it adds a very simple language feature upon which the
    community may choose to build (and evolve) facilities that implement
    additional rules and logic.

    My hope is that, if we can agree on something very small and simple,
    we can defer the more opinionated discussions about rules and logic to
    the community.

    In my opinion, language features should be simple, and consistent with
    the language - I believe the way to do that, is to avoid discussions
    about how such as facility should be used, and instead focus on how it
    should work. There is a lot of opinion built into the old Annotations
    RFC, and into Doctrine - features that attempt to dictate how the
    feature should be used. I don't believe the language should dictate
    what is or isn't correct or appropriate use.
    I think I like this, however a couple of simple questions:

    1) Any chance for (optionally) _naming_ annotations? It would be nice to be
    able to do: ->getAnnotation('table') and not have to handle unnecessary
    annotations
    not sure you need that, you can do this instead:
    ->getAnnotations(Table::class)
    however it won't throw an error if you have more than one "Table::class
    annotation" whereas I supposed you would expect so with a named annotation
    2) I like the idea of Hacks memoize for example, how do you see those being
    implemented? Or don't you?
    if Rasmus goal is to that "we can agree on something very small and
    simple" I guess it would best be left for another rfc
    3) When are annotations executed? On ->getAnnotations()? Every time?
    given they are context free, I suppose they would be executed on the
    first call only

    but what about this kind of annotation classes? :

    class Counter {
    private static $i = 0;
    private $n;
    function __construct() {
    $this->n = self::$i++;
    }
    function get() { return $this->n; }
    }

    both the getAnnotations() calls order and whether or not annotations are
    executed every time would make a difference
    Thanks,
    --
    Mathieu Rochette
  • Benjamin Eberlei at May 14, 2016 at 2:38 am

    On Fri, May 13, 2016 at 2:11 PM, Rasmus Schultz wrote:

    Dear Internals,

    I'm announcing a simplified RFC for annotations:

    https://wiki.php.net/rfc/simple-annotations

    It's an alternative to the proposed Attributes RFC and the (2010)
    Annotations RFC.

    I'm attempting with this to describe a feature that is closer to the
    language than what is proposed by the Attributes RFC, by permitting
    the use of any valid PHP expression as an annotation value.

    Where the Attributes RFC proposes new syntax for what is essentially
    arrays, this proposal instead permits you to use actual arrays, e.g.
    without inventing any new syntax. It also allows you to use values of
    any other type, including objects. This makes the proposed feature
    more immediately useful, with a minimal learning curve.
    The attributes RFC actually does not specific syntax or arrays, but either
    a scalar (number, string) or an ast\node.

    A proposal for arrays *would* actually be "closer to the language" as you
    describe it.

    Compared with the old Annotations RFC (and Doctrine Annotations, etc.)
    this proposal does not attempt to define or enforce any rules about
    what annotations are, permitted usage, inheritance rules, etc. -
    instead it adds a very simple language feature upon which the
    community may choose to build (and evolve) facilities that implement
    additional rules and logic.

    My hope is that, if we can agree on something very small and simple,
    we can defer the more opinionated discussions about rules and logic to
    the community.

    In my opinion, language features should be simple, and consistent with
    the language - I believe the way to do that, is to avoid discussions
    about how such as facility should be used, and instead focus on how it
    should work. There is a lot of opinion built into the old Annotations
    RFC, and into Doctrine - features that attempt to dictate how the
    feature should be used. I don't believe the language should dictate
    what is or isn't correct or appropriate use.

    Please review and comment.

    I see you took my question about context from the other thread and defined
    annotations to be context less.
    You should add to the RFC examples of what is happening, if you do access
    context, for example access to undefined variable notices:

    <<$x>>
    class Foo {}

    $refl = new ReflectionClass('Foo');
    var_dump($refl->getAttributes(Foo::class));
    // PHP Notice: Undefined variable: x in Command line code on line 1

    Still this is imho a weak point of your RFC. You already stated that a
    "simplified annotation" the way you see it is the expression wrapped in a
    closure:

    function () {
         return php-expression;
    }

    So if an annotation is a function/closure that belongs to its target
    (class, property, function, method, ...) then why wouldn't there be a way
    to specify arguments?
    The RFC should give an answer to that. The statement you add doesn't make
    sense without examples. How does dependency injection even work, when you
    don't have a context?

    "Annotations that do require context should explicitly ask for that context
    - for example, you could use an anonymous function, a callable, or an
    anonymous class, to provide context via dependency injection."

    greetings
    Benjamin

    Thanks,
    Rasmus Schultz

    --
    PHP Internals - PHP Runtime Development Mailing List
    To unsubscribe, visit: http://www.php.net/unsub.php
  • Rasmus Schultz at May 14, 2016 at 11:49 am
    Thank you for your comments!

    Benjamin,

    I have removed the comment about annotation expressions executing in
    an empty closure, since this example was clearly confusing, and I have
    tried to clarify the fact that annotation expressions execute in an
    empty scope. To be clear, annotation expressions are *not* closures,
    and they do not accept arguments - there is no reason to complicate
    the concept of annotations by introducing an implied scope, when you
    can introduce one explicitly, for example:

    class Validation {
         private $validate;

         public function __construct(callable $validate) {
             $this->validate = $validate;
         }

         public function validate($instance) {
             return call_user_func($this->validate, $instance);
         }
    }

    << new Validation(function (User $user) { return false !==
    filter_var($user->email, FILTER_VALIDATE_EMAIL); }) >>
    class User {
         public $email;
    }

    Of course, you could just as well do this with an interface - as it
    the case with most examples I can think of.

    If you can think of a meaningful annotation that actually requires
    context and can't be implemented in a better/safer/cleaner way with
    abstraction, please post? I'd like to add an example, but really have
    never seen one that can't be solved better without annotations.

    Marco,
    Love the simplicity of the RFC, but I can already see people doing terrible things with it
    Every language lets you do terrible and great things - I don't believe
    in putting up roadblocks and complicating the language that prevent
    people from learning.
    TBH, I'd rather just allow a constant array (with constant expressions only), and that would be good enough :-)
    I don't agree with the idea of crippling a language feature to prevent
    beginners from making mistakes - when doing so would also prevent
    static analysis and block experienced developers from doing useful
    things with objects.

    Davey and Mathieu,

    Annotations can be "named" by using classes. Per the RFC, defining or
    enforcing a rule about allowing only one instance of the same type, is
    not a feature.

    Hack's memoize is an annotation for the language interpreter itself -
    that's beyond the scope of this RFC, but could be implemented in the
    future.

    Your third question is answered by the RFC here:
    Annotation expressions are not evaluated until reflection is invoked, and are evaluated only once and internally memoized upon the first call to getAnnotations().
    Thank you for your input so far!

    The RFC is 0.2 with the last updates based on your feedback - I would
    like to add a suitable case example for annotations that require
    context before I'd say this RFC is 1.0.

    If anyone can point at a real case example using Doctrine Annotations
    (or anything else) please do!

    Thanks,
       Rasmus

    On Sat, May 14, 2016 at 4:38 AM, Benjamin Eberlei wrote:

    On Fri, May 13, 2016 at 2:11 PM, Rasmus Schultz wrote:

    Dear Internals,

    I'm announcing a simplified RFC for annotations:

    https://wiki.php.net/rfc/simple-annotations

    It's an alternative to the proposed Attributes RFC and the (2010)
    Annotations RFC.

    I'm attempting with this to describe a feature that is closer to the
    language than what is proposed by the Attributes RFC, by permitting
    the use of any valid PHP expression as an annotation value.

    Where the Attributes RFC proposes new syntax for what is essentially
    arrays, this proposal instead permits you to use actual arrays, e.g.
    without inventing any new syntax. It also allows you to use values of
    any other type, including objects. This makes the proposed feature
    more immediately useful, with a minimal learning curve.

    The attributes RFC actually does not specific syntax or arrays, but either a
    scalar (number, string) or an ast\node.

    A proposal for arrays *would* actually be "closer to the language" as you
    describe it.
    Compared with the old Annotations RFC (and Doctrine Annotations, etc.)
    this proposal does not attempt to define or enforce any rules about
    what annotations are, permitted usage, inheritance rules, etc. -
    instead it adds a very simple language feature upon which the
    community may choose to build (and evolve) facilities that implement
    additional rules and logic.

    My hope is that, if we can agree on something very small and simple,
    we can defer the more opinionated discussions about rules and logic to
    the community.

    In my opinion, language features should be simple, and consistent with
    the language - I believe the way to do that, is to avoid discussions
    about how such as facility should be used, and instead focus on how it
    should work. There is a lot of opinion built into the old Annotations
    RFC, and into Doctrine - features that attempt to dictate how the
    feature should be used. I don't believe the language should dictate
    what is or isn't correct or appropriate use.

    Please review and comment.

    I see you took my question about context from the other thread and defined
    annotations to be context less.
    You should add to the RFC examples of what is happening, if you do access
    context, for example access to undefined variable notices:

    <<$x>>
    class Foo {}

    $refl = new ReflectionClass('Foo');
    var_dump($refl->getAttributes(Foo::class));
    // PHP Notice: Undefined variable: x in Command line code on line 1

    Still this is imho a weak point of your RFC. You already stated that a
    "simplified annotation" the way you see it is the expression wrapped in a
    closure:

    function () {
    return php-expression;
    }

    So if an annotation is a function/closure that belongs to its target (class,
    property, function, method, ...) then why wouldn't there be a way to specify
    arguments?
    The RFC should give an answer to that. The statement you add doesn't make
    sense without examples. How does dependency injection even work, when you
    don't have a context?

    "Annotations that do require context should explicitly ask for that context
    - for example, you could use an anonymous function, a callable, or an
    anonymous class, to provide context via dependency injection."

    greetings
    Benjamin
    Thanks,
    Rasmus Schultz

    --
    PHP Internals - PHP Runtime Development Mailing List
    To unsubscribe, visit: http://www.php.net/unsub.php
  • Dan Ackroyd at May 14, 2016 at 12:32 pm

    On 14 May 2016 at 12:48, Rasmus Schultz wrote:
    Hack's memoize is an annotation for the language interpreter itself -
    that's beyond the scope of this RFC, but could be implemented in the
    future.
    Please can you add something to the RFC that reserves the possibility
    to do this, so that it can be introduced in a BC compatible way in the
    future?

    Hand-waving away problems and saying that they aren't in scope is a
    sure-fire way to build deficiencies into a design.

    This is not a smaller problem in userland code, as it is easy for
    people to migrate from one library to another, but is almost
    impossible to overcome in core PHP, where any BC-breaking change
    causes lots of difficultly for end-users.

    cheers
    Dan
  • Benjamin Eberlei at May 14, 2016 at 1:41 pm

    On Sat, May 14, 2016 at 1:48 PM, Rasmus Schultz wrote:

    Thank you for your comments!

    Benjamin,

    I have removed the comment about annotation expressions executing in
    an empty closure, since this example was clearly confusing, and I have
    tried to clarify the fact that annotation expressions execute in an
    empty scope. To be clear, annotation expressions are *not* closures,
    and they do not accept arguments - there is no reason to complicate
    the concept of annotations by introducing an implied scope, when you
    can introduce one explicitly, for example:

    class Validation {
    private $validate;

    public function __construct(callable $validate) {
    $this->validate = $validate;
    }

    public function validate($instance) {
    return call_user_func($this->validate, $instance);
    }
    }

    << new Validation(function (User $user) { return false !==
    filter_var($user->email, FILTER_VALIDATE_EMAIL); }) >>
    class User {
    public $email;
    }

    Of course, you could just as well do this with an interface - as it
    the case with most examples I can think of.

    If you can think of a meaningful annotation that actually requires
    context and can't be implemented in a better/safer/cleaner way with
    abstraction, please post? I'd like to add an example, but really have
    never seen one that can't be solved better without annotations.
    Every proposal before was about annotation/attributes as metadata for code.
    Your proposal makes them executable functions instead (nameless, attached
    to code blocks).

    I think this is just way out of scope of what the 80% want to achieve with
    this feature.
    Marco,
    Love the simplicity of the RFC, but I can already see people doing
    terrible things with it

    Every language lets you do terrible and great things - I don't believe
    in putting up roadblocks and complicating the language that prevent
    people from learning.
    TBH, I'd rather just allow a constant array (with constant expressions
    only), and that would be good enough :-)

    I don't agree with the idea of crippling a language feature to prevent
    beginners from making mistakes - when doing so would also prevent
    static analysis and block experienced developers from doing useful
    things with objects.

    Davey and Mathieu,

    Annotations can be "named" by using classes. Per the RFC, defining or
    enforcing a rule about allowing only one instance of the same type, is
    not a feature.

    Hack's memoize is an annotation for the language interpreter itself -
    that's beyond the scope of this RFC, but could be implemented in the
    future.

    Your third question is answered by the RFC here:
    Annotation expressions are not evaluated until reflection is invoked,
    and are evaluated only once and internally memoized upon the first call to
    getAnnotations().

    Thank you for your input so far!

    The RFC is 0.2 with the last updates based on your feedback - I would
    like to add a suitable case example for annotations that require
    context before I'd say this RFC is 1.0.

    If anyone can point at a real case example using Doctrine Annotations
    (or anything else) please do!

    Thanks,
    Rasmus

    On Sat, May 14, 2016 at 4:38 AM, Benjamin Eberlei wrote:

    On Fri, May 13, 2016 at 2:11 PM, Rasmus Schultz wrote:

    Dear Internals,

    I'm announcing a simplified RFC for annotations:

    https://wiki.php.net/rfc/simple-annotations

    It's an alternative to the proposed Attributes RFC and the (2010)
    Annotations RFC.

    I'm attempting with this to describe a feature that is closer to the
    language than what is proposed by the Attributes RFC, by permitting
    the use of any valid PHP expression as an annotation value.

    Where the Attributes RFC proposes new syntax for what is essentially
    arrays, this proposal instead permits you to use actual arrays, e.g.
    without inventing any new syntax. It also allows you to use values of
    any other type, including objects. This makes the proposed feature
    more immediately useful, with a minimal learning curve.

    The attributes RFC actually does not specific syntax or arrays, but either a
    scalar (number, string) or an ast\node.

    A proposal for arrays *would* actually be "closer to the language" as you
    describe it.
    Compared with the old Annotations RFC (and Doctrine Annotations, etc.)
    this proposal does not attempt to define or enforce any rules about
    what annotations are, permitted usage, inheritance rules, etc. -
    instead it adds a very simple language feature upon which the
    community may choose to build (and evolve) facilities that implement
    additional rules and logic.

    My hope is that, if we can agree on something very small and simple,
    we can defer the more opinionated discussions about rules and logic to
    the community.

    In my opinion, language features should be simple, and consistent with
    the language - I believe the way to do that, is to avoid discussions
    about how such as facility should be used, and instead focus on how it
    should work. There is a lot of opinion built into the old Annotations
    RFC, and into Doctrine - features that attempt to dictate how the
    feature should be used. I don't believe the language should dictate
    what is or isn't correct or appropriate use.

    Please review and comment.

    I see you took my question about context from the other thread and defined
    annotations to be context less.
    You should add to the RFC examples of what is happening, if you do access
    context, for example access to undefined variable notices:

    <<$x>>
    class Foo {}

    $refl = new ReflectionClass('Foo');
    var_dump($refl->getAttributes(Foo::class));
    // PHP Notice: Undefined variable: x in Command line code on line 1

    Still this is imho a weak point of your RFC. You already stated that a
    "simplified annotation" the way you see it is the expression wrapped in a
    closure:

    function () {
    return php-expression;
    }

    So if an annotation is a function/closure that belongs to its target (class,
    property, function, method, ...) then why wouldn't there be a way to specify
    arguments?
    The RFC should give an answer to that. The statement you add doesn't make
    sense without examples. How does dependency injection even work, when you
    don't have a context?

    "Annotations that do require context should explicitly ask for that context
    - for example, you could use an anonymous function, a callable, or an
    anonymous class, to provide context via dependency injection."

    greetings
    Benjamin
    Thanks,
    Rasmus Schultz

    --
    PHP Internals - PHP Runtime Development Mailing List
    To unsubscribe, visit: http://www.php.net/unsub.php
  • Rasmus Schultz at May 14, 2016 at 7:50 pm
    Dan,

    I've added a note about special annotations to the "future scope"
    section, naming the memoization-annotation as an example.

    Benjamin,

    I don't think you mean "out of scope" of what 80% want, I think you
    mean "beyond the scope"?

    I think this will definitely cover what 80% want to achieve, and
    possibly a lot more - possibly new and useful patterns that we can't
    even predict.

    On Sat, May 14, 2016 at 3:41 PM, Benjamin Eberlei wrote:

    On Sat, May 14, 2016 at 1:48 PM, Rasmus Schultz wrote:

    Thank you for your comments!

    Benjamin,

    I have removed the comment about annotation expressions executing in
    an empty closure, since this example was clearly confusing, and I have
    tried to clarify the fact that annotation expressions execute in an
    empty scope. To be clear, annotation expressions are *not* closures,
    and they do not accept arguments - there is no reason to complicate
    the concept of annotations by introducing an implied scope, when you
    can introduce one explicitly, for example:

    class Validation {
    private $validate;

    public function __construct(callable $validate) {
    $this->validate = $validate;
    }

    public function validate($instance) {
    return call_user_func($this->validate, $instance);
    }
    }

    << new Validation(function (User $user) { return false !==
    filter_var($user->email, FILTER_VALIDATE_EMAIL); }) >>
    class User {
    public $email;
    }

    Of course, you could just as well do this with an interface - as it
    the case with most examples I can think of.

    If you can think of a meaningful annotation that actually requires
    context and can't be implemented in a better/safer/cleaner way with
    abstraction, please post? I'd like to add an example, but really have
    never seen one that can't be solved better without annotations.

    Every proposal before was about annotation/attributes as metadata for code.
    Your proposal makes them executable functions instead (nameless, attached to
    code blocks).

    I think this is just way out of scope of what the 80% want to achieve with
    this feature.

    Marco,
    Love the simplicity of the RFC, but I can already see people doing
    terrible things with it
    Every language lets you do terrible and great things - I don't believe
    in putting up roadblocks and complicating the language that prevent
    people from learning.
    TBH, I'd rather just allow a constant array (with constant expressions
    only), and that would be good enough :-)
    I don't agree with the idea of crippling a language feature to prevent
    beginners from making mistakes - when doing so would also prevent
    static analysis and block experienced developers from doing useful
    things with objects.

    Davey and Mathieu,

    Annotations can be "named" by using classes. Per the RFC, defining or
    enforcing a rule about allowing only one instance of the same type, is
    not a feature.

    Hack's memoize is an annotation for the language interpreter itself -
    that's beyond the scope of this RFC, but could be implemented in the
    future.

    Your third question is answered by the RFC here:
    Annotation expressions are not evaluated until reflection is invoked,
    and are evaluated only once and internally memoized upon the first call to
    getAnnotations().
    Thank you for your input so far!

    The RFC is 0.2 with the last updates based on your feedback - I would
    like to add a suitable case example for annotations that require
    context before I'd say this RFC is 1.0.

    If anyone can point at a real case example using Doctrine Annotations
    (or anything else) please do!

    Thanks,
    Rasmus


    On Sat, May 14, 2016 at 4:38 AM, Benjamin Eberlei <kontakt@beberlei.de>
    wrote:

    On Fri, May 13, 2016 at 2:11 PM, Rasmus Schultz <rasmus@mindplay.dk>
    wrote:
    Dear Internals,

    I'm announcing a simplified RFC for annotations:

    https://wiki.php.net/rfc/simple-annotations

    It's an alternative to the proposed Attributes RFC and the (2010)
    Annotations RFC.

    I'm attempting with this to describe a feature that is closer to the
    language than what is proposed by the Attributes RFC, by permitting
    the use of any valid PHP expression as an annotation value.

    Where the Attributes RFC proposes new syntax for what is essentially
    arrays, this proposal instead permits you to use actual arrays, e.g.
    without inventing any new syntax. It also allows you to use values of
    any other type, including objects. This makes the proposed feature
    more immediately useful, with a minimal learning curve.

    The attributes RFC actually does not specific syntax or arrays, but
    either a
    scalar (number, string) or an ast\node.

    A proposal for arrays *would* actually be "closer to the language" as
    you
    describe it.
    Compared with the old Annotations RFC (and Doctrine Annotations, etc.)
    this proposal does not attempt to define or enforce any rules about
    what annotations are, permitted usage, inheritance rules, etc. -
    instead it adds a very simple language feature upon which the
    community may choose to build (and evolve) facilities that implement
    additional rules and logic.

    My hope is that, if we can agree on something very small and simple,
    we can defer the more opinionated discussions about rules and logic to
    the community.

    In my opinion, language features should be simple, and consistent with
    the language - I believe the way to do that, is to avoid discussions
    about how such as facility should be used, and instead focus on how it
    should work. There is a lot of opinion built into the old Annotations
    RFC, and into Doctrine - features that attempt to dictate how the
    feature should be used. I don't believe the language should dictate
    what is or isn't correct or appropriate use.

    Please review and comment.

    I see you took my question about context from the other thread and
    defined
    annotations to be context less.
    You should add to the RFC examples of what is happening, if you do
    access
    context, for example access to undefined variable notices:

    <<$x>>
    class Foo {}

    $refl = new ReflectionClass('Foo');
    var_dump($refl->getAttributes(Foo::class));
    // PHP Notice: Undefined variable: x in Command line code on line 1

    Still this is imho a weak point of your RFC. You already stated that a
    "simplified annotation" the way you see it is the expression wrapped in
    a
    closure:

    function () {
    return php-expression;
    }

    So if an annotation is a function/closure that belongs to its target
    (class,
    property, function, method, ...) then why wouldn't there be a way to
    specify
    arguments?
    The RFC should give an answer to that. The statement you add doesn't
    make
    sense without examples. How does dependency injection even work, when
    you
    don't have a context?

    "Annotations that do require context should explicitly ask for that
    context
    - for example, you could use an anonymous function, a callable, or an
    anonymous class, to provide context via dependency injection."

    greetings
    Benjamin
    Thanks,
    Rasmus Schultz

    --
    PHP Internals - PHP Runtime Development Mailing List
    To unsubscribe, visit: http://www.php.net/unsub.php
  • Rowan Collins at May 16, 2016 at 9:18 am

    On 14/05/2016 20:49, Rasmus Schultz wrote:
    Dan,

    I've added a note about special annotations to the "future scope"
    section, naming the memoization-annotation as an example.
    This doesn't really explain how such a feature would fit it into the
    proposal. For instance, how can we avoid the syntax clashing with
    existing userland issues? Given that annotations in this proposal don't
    have names, we can't just reserve all names beginning "__" or "php\".

    Perhaps they would be pseudo-function calls, like <<__memoize()>>? How
    would that (or any other undefined function) act if accessed on a
    version that didn't have the feature?

    I realise you don't want to define the details, but an idea of what an
    annotation targeting the engine would look like would make the
    future-proofing clearer.

    Regards,
    --
    Rowan Collins
    [IMSoP]
  • Fleshgrinder at May 16, 2016 at 10:38 am

    On 5/13/2016 2:11 PM, Rasmus Schultz wrote:
    Dear Internals,

    I'm announcing a simplified RFC for annotations:

    https://wiki.php.net/rfc/simple-annotations
    -1 again, I am sorry.

    The problem is that an annotation by definition is just meta-data. Your
    proposal however might result in fatal errors from meta-data:

       $reflector = new ReflectionClass(User::class);
       $reflector->getAnnotations();

       // Fatal error: Uncaught Error: Class 'TableName' not found ...

    This is an absolute No-Go for meta-data.

    --
    Richard "Fleshgrinder" Fussenegger
  • Fleshgrinder at May 16, 2016 at 10:41 am

    On 5/13/2016 2:57 PM, Davey Shafik wrote:
    2) I like the idea of Hacks memoize for example, how do you see those being
    implemented? Or don't you?
    I wrote it in the /attribute grammar/ thread and I write it here again.
    Stuff like memoize should be implemented as keywords as part of the
    language and not via annotations.

       memoized function f() {}

    Same goes for deprecated:

       deprecated memoized function f() {}

    Or other special effects:

       deprecated inlined memoized function f() {}

    These things are not meta-data for userland, they are meta-data for PHP
    and should be part of, well, PHP.

    --
    Richard "Fleshgrinder" Fussenegger
  • Rasmus Schultz at May 16, 2016 at 1:05 pm
    Rowan,

    I'm afraid I don't follow. Why is it a problem to simply add a
    function or class to the global namespace?

    << new Memoize() >>

    or maybe a class with factory functions for built-in annotations:

    << Meta::memoize() >>

    I tend to agree with Richard though, that system directives really
    ought to be supported by the language with keywords rather than
    annotations.

    Richard,

    Regarding your point of view:
    The problem is that an annotation by definition is just meta-data. Your
    proposal however might result in fatal errors from meta-data
    I agree that annotations are just meta-data. Values.

    I disagree that we can't permit the use of PHP expressions to generate
    those values.

    You can't eliminate problems such as missing classes - and you
    shouldn't. With the examples in the Attributes RFC, as well as with
    e.g. Doctrine Annotations, we have the exact same problems, they're
    just one step removed from the language feature, which only adds
    complexity and makes it harder to debug these things.

    The only work-around to an issue such as a missing class, is to
    complete ignore the annotation - which leads to undefined behavior and
    scenarios that are even harder to debug.

    The other big problem with this position, is that it goes more or less
    directly against what the community wants - the majority of those who
    use annotations in PHP today, use Doctrine Annotations, and they
    expect annotations as classes.

    Source code can contain errors. I don't think there's really any way
    around that. Even if you wittled down metadata to the absolute minimum
    - a string, such as what it is in Go code, that string is invariably
    going to contain something that needs to be parsed or interpreted
    somehow, somewhere, at some point, and it can lead to errors.

    In my opinion, it's better to allow those errors to be caught early -
    for example, being able to catch syntax errors in expressions already
    at load-time. The attributes RFC is much worse in this regard - you
    could be lugging around all kinds of dependency errors, missing
    classes and whatnot, and you'd never know about it until the day you
    hit one of those annotations. Now instead, you're just stuck having to
    type out redundant unit-tests to prove that every annotation is valid,
    when the language could have taken care of that in a much simpler way.

    The other issue is dependencies. The Attributes RFC will lead to code
    with all sorts of hidden dependencies - possibly dependencies that you
    can't even know about, because you can't know how your metadata is
    going to be interpreted precisely. You can't know which classes your
    metadata might get mapped to or how. Simple Annotations take care of
    that, and they force you to e.g. `composer require` the package that
    provides the annotation classes you're using - this is a good thing.

    Hiding dependencies makes it really difficult for others to reason
    about your code. The Attributes RFC will lead to a lot of hidden rules
    - whereas Simple Annotations are simple and straight-forward, nothing
    hidden or implicit, your dependencies visible and traceable, which
    will lead to much better tooling. For example, an IDE or offline code
    analysis tool would catch syntax errors and missing classes and warn
    about those right away.

    I'm sorry, but I think that the idea of meta-data that can't error
    somehow, somewhere, at some point, is completely unrealistic.

    And I'd much rather have a simple facility that enables those errors
    to surface quickly.

    On Mon, May 16, 2016 at 11:16 AM, Rowan Collins wrote:
    On 14/05/2016 20:49, Rasmus Schultz wrote:

    Dan,

    I've added a note about special annotations to the "future scope"
    section, naming the memoization-annotation as an example.

    This doesn't really explain how such a feature would fit it into the
    proposal. For instance, how can we avoid the syntax clashing with existing
    userland issues? Given that annotations in this proposal don't have names,
    we can't just reserve all names beginning "__" or "php\".

    Perhaps they would be pseudo-function calls, like <<__memoize()>>? How would
    that (or any other undefined function) act if accessed on a version that
    didn't have the feature?

    I realise you don't want to define the details, but an idea of what an
    annotation targeting the engine would look like would make the
    future-proofing clearer.

    Regards,
    --
    Rowan Collins
    [IMSoP]




    --
    PHP Internals - PHP Runtime Development Mailing List
    To unsubscribe, visit: http://www.php.net/unsub.php
  • Rowan Collins at May 16, 2016 at 5:23 pm

    On 16/05/2016 14:05, Rasmus Schultz wrote:
    I'm afraid I don't follow. Why is it a problem to simply add a
    function or class to the global namespace?

    << new Memoize() >>

    or maybe a class with factory functions for built-in annotations:

    << Meta::memoize() >>
    Well, those particular names look quite likely to collide with users' code, though I guess more obviously reserved names could be used.

    More generally, though, neither feels a natural fit, because of the need to specify a value, rather than a name. On Reflection, what would an instance of class Memoize look like? Could you call "new Memoize" somewhere else?

    If a memoize() function was executed, what value would it return? Since you can only see the evaluated value, how could you detect the annotation for debugging?

    Indeed, if we're interested only in values, not where they come from, are the following all equivalent, and the mechanics totally unndetectable by Reflection?

    <<null>>

    <<(function(){return null;})()>>

    function foo() { return null; }
    << foo() >>

    If the function form doesn't receive any context, its only purpose would be to copy some runtime global state into the annotation value on first access, which seems like a strange thing to do.

    I tend to agree with Richard though, that system directives really
    ought to be supported by the language with keywords rather than
    annotations.
    That would be one way around it, indeed, so rather than "Future Scope",
    you could label "compiler directive" type annotations as "deliberately
    out of scope".

    Regards,
    --
    Rowan Collins
    [IMSoP]
  • Fleshgrinder at May 16, 2016 at 6:40 pm

    On 5/16/2016 3:05 PM, Rasmus Schultz wrote:
    I'm sorry, but I think that the idea of meta-data that can't error
    somehow, somewhere, at some point, is completely unrealistic.

    And I'd much rather have a simple facility that enables those errors
    to surface quickly.
    It should error and it should error exactly at the point when you want
    to use it and at no other point. Right now they will error anytime
    anyone wants to do anything with any annotation.

    I fully understand the urge to directly access objects and I actually
    support it and I want them to error out at the point where you try to
    instantiate them. However, not when I simply access annotations in
    introspection.

    According to your logic I have to load the whole dependency chain, even
    thought I just want to generate my documentation that might have some
    annotations in use. I also need to load all my dependencies even though
    I wanted to leave the security dependency out because I wanted to easily
    disable the security annotation system locally for development. I even
    have to load the whole dependency chain, even though I just want to
    introspect the single data structure at hand without invoking anything.

    Even worse if I am using a package that has Doctrine annotations but I
    use it without them: /fatal error/

    Nice? No!

    Solutions?

    Make the /simple/ annotations /simple/. ;-)

    Only allow scalar data to be defined and allow userland to register
    themselves for specific annotations. I mentioned this before but somehow
    everyone wants something more fancy and I have no karma (even though
    requested but ignored) to write my own RFC. That being said, you have
    the ability to write an RFC so please just take it. :-)

    Some PHP code to illustrate what I was thinking of since I am better
    with code than with words. :-P

    https://gist.github.com/Fleshgrinder/d26cd4751827b8c10a0dc33da32b48c3

    Reflection is the wrong tool for the job to build annotation systems.
    Reflection should not be used in production it should be used to
    introspect data structures and reason about them or other stuff during
    unit tests.

    However, reflection should provide the ability to read annotations, it
    just does not do anything with them by default and outputs stupid
    arrays. You will definitely understand what I mean it you follow the Gist.

    I am sure there is room for improvement and that I overlooked something
    in my Gist. But I think it is a starting point, some additional notes:

    - I do not see any benefit in annotations for parameters.
    - I do not see any benefit in annotations for Generators.
    - I do not see any benefit for annotations in php-src.

    My proposal would include to ban annotations from php-src and make it a
    pure userland functionality. This has many advantages:

    - No name collisions.
    - Clear policy for the future.
    - php-src features are never optional.
    - php-src does not provide meta-data.

    Let me know what you think or if you have questions in regards to the
    Gist that are unclear. (Or maybe you found mistakes.)

    --
    Richard "Fleshgrinder" Fussenegger
  • Rasmus Schultz at May 17, 2016 at 9:06 am
    Richard,

    I believe I have already stated my position on all of these concerns
    in my last email.

    Short recap:

    There's no such thing as optional dependencies - if you depend on a
    Doctrine ORM annotation, you depend on that package.

    The code should (must) error the moment you try to instantiate those
    annotations - whether you intend to use them or not is besides the
    question - a missing class is an error, in annotations as it is
    anywhere else in your code.

    Silently ignoring missing annotations solves nothing - it just leads
    to errors that are even harder to find and debug.

    You seem awfully concerned about name collisions? Most packages use a
    vendor\package namespace convention now - PHP has always been adding
    things to the global namespace, and it's never been a really
    substantial problem. I'm not that concerned.

    The one new thing you brought up here, is the issue of potentially
    loading/instantiating a bunch of annotations that go unused. From a
    dependency point of view, I maintain that that's correct and it should
    error out on missing classes.

    From a performance point of view, you may have a valid concern, and
    this had occurred to me before - but I decided to leave it alone, for
    a couple of reasons. The most important reason being, look at how
    annotations get used in practice: controllers get things like route
    and filter annotations, all of which are usually needed at the same
    time; entities get ORM annotations, all of which are usually needed at
    the same time; form models get validation and input-type annotations,
    all of which are usually needed at the same time. And so on.

    The fact of the matter is that classes tend to have a single
    responsibility, and this usually means that applicable annotations
    tend to belong to a specific domain, and are needed at the same time.

    In other words, this problem is pretty theoretical - in reality, it's
    a very small problem, which, if somebody was very concerned about,
    could absolutely be solved in userland, by adding a cache layer. Which
    projects like Doctrine Annotations would likely do anyway, in order to
    cache the result of mode complex annotation logic to control
    inheritance, cardinality, applicability, etc. - all the complex stuff
    that this RFC stays away from.

    The extreme case of what you're proposing, is what Go does - an
    annotation is simply a string. No chance of any error, anywhere, ever,
    right? Wrong. People put JSON data in those strings for example, and
    parsing that data leads to run-time errors instead. That's the extreme
    example, but the problem with what you're proposing is precisely the
    same: you allow something like nested array data structures, those are
    still going to get interpreted and mapped to objects at run-time, and
    it leads to run-time errors instead.

    I maintain that the majority use-case is object annotations - and that
    deferring the construction of those objects doesn't solve anything.

    You're just deferring or hiding the problem, adding complexity, and
    mental as well as practical debugging effort - but the problem doesn't
    go away.

    I am and will always be in favor of language design that takes the
    most direct route to satisfy a requirement. In this case, the
    requirement is annotations as objects - and the most natural and
    direct route is the "new" keyword, static method calls, or whatever
    way you normally create objects; inventing a more indirect way to do
    that just adds complexity.

    On Mon, May 16, 2016 at 8:39 PM, Fleshgrinder wrote:
    On 5/16/2016 3:05 PM, Rasmus Schultz wrote:
    I'm sorry, but I think that the idea of meta-data that can't error
    somehow, somewhere, at some point, is completely unrealistic.

    And I'd much rather have a simple facility that enables those errors
    to surface quickly.
    It should error and it should error exactly at the point when you want
    to use it and at no other point. Right now they will error anytime
    anyone wants to do anything with any annotation.

    I fully understand the urge to directly access objects and I actually
    support it and I want them to error out at the point where you try to
    instantiate them. However, not when I simply access annotations in
    introspection.

    According to your logic I have to load the whole dependency chain, even
    thought I just want to generate my documentation that might have some
    annotations in use. I also need to load all my dependencies even though
    I wanted to leave the security dependency out because I wanted to easily
    disable the security annotation system locally for development. I even
    have to load the whole dependency chain, even though I just want to
    introspect the single data structure at hand without invoking anything.

    Even worse if I am using a package that has Doctrine annotations but I
    use it without them: /fatal error/

    Nice? No!

    Solutions?

    Make the /simple/ annotations /simple/. ;-)

    Only allow scalar data to be defined and allow userland to register
    themselves for specific annotations. I mentioned this before but somehow
    everyone wants something more fancy and I have no karma (even though
    requested but ignored) to write my own RFC. That being said, you have
    the ability to write an RFC so please just take it. :-)

    Some PHP code to illustrate what I was thinking of since I am better
    with code than with words. :-P

    https://gist.github.com/Fleshgrinder/d26cd4751827b8c10a0dc33da32b48c3

    Reflection is the wrong tool for the job to build annotation systems.
    Reflection should not be used in production it should be used to
    introspect data structures and reason about them or other stuff during
    unit tests.

    However, reflection should provide the ability to read annotations, it
    just does not do anything with them by default and outputs stupid
    arrays. You will definitely understand what I mean it you follow the Gist.

    I am sure there is room for improvement and that I overlooked something
    in my Gist. But I think it is a starting point, some additional notes:

    - I do not see any benefit in annotations for parameters.
    - I do not see any benefit in annotations for Generators.
    - I do not see any benefit for annotations in php-src.

    My proposal would include to ban annotations from php-src and make it a
    pure userland functionality. This has many advantages:

    - No name collisions.
    - Clear policy for the future.
    - php-src features are never optional.
    - php-src does not provide meta-data.

    Let me know what you think or if you have questions in regards to the
    Gist that are unclear. (Or maybe you found mistakes.)

    --
    Richard "Fleshgrinder" Fussenegger
  • Rasmus Schultz at May 17, 2016 at 2:22 pm
    I'd like to finish this RFC, but I have two remaining issues.

    The syntax is a minor issue - since any valid PHP expression can be
    used, the bit-shift ambiguity is technically an issue, however
    marginal.

    A lot of people commented on the syntax when I posted the RFC on
    reddit - they don't like it.

    Anyone have any ideas for an alternative syntax? It needs to be
    delimited, e.g. needs to use opening and closing delimiters or a
    recognizable opening delimiter... Here's some ideas:

    @{ new Table("user") }

    @[ new Table("user") ]

    {{ new Table("user") }}

    +{ new Table("user") }

    I don't like any of these really, but the bit-shift operator isn't
    going when the stuff inside is an expression which could include
    bit-shift (is it?)

    The other issue is the dependency (context) injection example - no one
    seems to be able to cite an actual use-case, and if that's the case, I
    should probably just remove it from the RFC entirely?

    @Larry can you think of a case example in the myriad annotations
    you've seen in Drupal code? :-)

    Anyone else using Doctrine Annotations actually seen anyone making use
    of a closure in an annotation?

    On Tue, May 17, 2016 at 11:06 AM, Rasmus Schultz wrote:
    Richard,

    I believe I have already stated my position on all of these concerns
    in my last email.

    Short recap:

    There's no such thing as optional dependencies - if you depend on a
    Doctrine ORM annotation, you depend on that package.

    The code should (must) error the moment you try to instantiate those
    annotations - whether you intend to use them or not is besides the
    question - a missing class is an error, in annotations as it is
    anywhere else in your code.

    Silently ignoring missing annotations solves nothing - it just leads
    to errors that are even harder to find and debug.

    You seem awfully concerned about name collisions? Most packages use a
    vendor\package namespace convention now - PHP has always been adding
    things to the global namespace, and it's never been a really
    substantial problem. I'm not that concerned.

    The one new thing you brought up here, is the issue of potentially
    loading/instantiating a bunch of annotations that go unused. From a
    dependency point of view, I maintain that that's correct and it should
    error out on missing classes.

    From a performance point of view, you may have a valid concern, and
    this had occurred to me before - but I decided to leave it alone, for
    a couple of reasons. The most important reason being, look at how
    annotations get used in practice: controllers get things like route
    and filter annotations, all of which are usually needed at the same
    time; entities get ORM annotations, all of which are usually needed at
    the same time; form models get validation and input-type annotations,
    all of which are usually needed at the same time. And so on.

    The fact of the matter is that classes tend to have a single
    responsibility, and this usually means that applicable annotations
    tend to belong to a specific domain, and are needed at the same time.

    In other words, this problem is pretty theoretical - in reality, it's
    a very small problem, which, if somebody was very concerned about,
    could absolutely be solved in userland, by adding a cache layer. Which
    projects like Doctrine Annotations would likely do anyway, in order to
    cache the result of mode complex annotation logic to control
    inheritance, cardinality, applicability, etc. - all the complex stuff
    that this RFC stays away from.

    The extreme case of what you're proposing, is what Go does - an
    annotation is simply a string. No chance of any error, anywhere, ever,
    right? Wrong. People put JSON data in those strings for example, and
    parsing that data leads to run-time errors instead. That's the extreme
    example, but the problem with what you're proposing is precisely the
    same: you allow something like nested array data structures, those are
    still going to get interpreted and mapped to objects at run-time, and
    it leads to run-time errors instead.

    I maintain that the majority use-case is object annotations - and that
    deferring the construction of those objects doesn't solve anything.

    You're just deferring or hiding the problem, adding complexity, and
    mental as well as practical debugging effort - but the problem doesn't
    go away.

    I am and will always be in favor of language design that takes the
    most direct route to satisfy a requirement. In this case, the
    requirement is annotations as objects - and the most natural and
    direct route is the "new" keyword, static method calls, or whatever
    way you normally create objects; inventing a more indirect way to do
    that just adds complexity.

    On Mon, May 16, 2016 at 8:39 PM, Fleshgrinder wrote:
    On 5/16/2016 3:05 PM, Rasmus Schultz wrote:
    I'm sorry, but I think that the idea of meta-data that can't error
    somehow, somewhere, at some point, is completely unrealistic.

    And I'd much rather have a simple facility that enables those errors
    to surface quickly.
    It should error and it should error exactly at the point when you want
    to use it and at no other point. Right now they will error anytime
    anyone wants to do anything with any annotation.

    I fully understand the urge to directly access objects and I actually
    support it and I want them to error out at the point where you try to
    instantiate them. However, not when I simply access annotations in
    introspection.

    According to your logic I have to load the whole dependency chain, even
    thought I just want to generate my documentation that might have some
    annotations in use. I also need to load all my dependencies even though
    I wanted to leave the security dependency out because I wanted to easily
    disable the security annotation system locally for development. I even
    have to load the whole dependency chain, even though I just want to
    introspect the single data structure at hand without invoking anything.

    Even worse if I am using a package that has Doctrine annotations but I
    use it without them: /fatal error/

    Nice? No!

    Solutions?

    Make the /simple/ annotations /simple/. ;-)

    Only allow scalar data to be defined and allow userland to register
    themselves for specific annotations. I mentioned this before but somehow
    everyone wants something more fancy and I have no karma (even though
    requested but ignored) to write my own RFC. That being said, you have
    the ability to write an RFC so please just take it. :-)

    Some PHP code to illustrate what I was thinking of since I am better
    with code than with words. :-P

    https://gist.github.com/Fleshgrinder/d26cd4751827b8c10a0dc33da32b48c3

    Reflection is the wrong tool for the job to build annotation systems.
    Reflection should not be used in production it should be used to
    introspect data structures and reason about them or other stuff during
    unit tests.

    However, reflection should provide the ability to read annotations, it
    just does not do anything with them by default and outputs stupid
    arrays. You will definitely understand what I mean it you follow the Gist.

    I am sure there is room for improvement and that I overlooked something
    in my Gist. But I think it is a starting point, some additional notes:

    - I do not see any benefit in annotations for parameters.
    - I do not see any benefit in annotations for Generators.
    - I do not see any benefit for annotations in php-src.

    My proposal would include to ban annotations from php-src and make it a
    pure userland functionality. This has many advantages:

    - No name collisions.
    - Clear policy for the future.
    - php-src features are never optional.
    - php-src does not provide meta-data.

    Let me know what you think or if you have questions in regards to the
    Gist that are unclear. (Or maybe you found mistakes.)

    --
    Richard "Fleshgrinder" Fussenegger
  • Rowan Collins at May 17, 2016 at 3:30 pm

    On 17/05/2016 15:22, Rasmus Schultz wrote:
    The other issue is the dependency (context) injection example - no one
    seems to be able to cite an actual use-case, and if that's the case, I
    should probably just remove it from the RFC entirely?

    @Larry can you think of a case example in the myriad annotations
    you've seen in Drupal code? :-)

    Anyone else using Doctrine Annotations actually seen anyone making use
    of a closure in an annotation?
    Possibly nobody's responded to your call for an example because they're
    not sure what it is you're asking for an example of. I don't really
    understand what closures have to do with annotations, or how that
    relates to capturing context.

    An example from the other thread of a context-bound annotation would be
    implementing validation like this:

    <<ValidateRange($percentage, 0, 100)>>
    function foo(int $percentage)


    This would appear to be unsupported as such by your proposal, so you
    would instead just have to use strings to represent how it needed to be
    accessed:

    <<new ValidateRangeAnnotation('$percentage', 0, 100)>>

    and then have extra machinery in the reflection logic to extract the
    parameters and pass them to the object, e.g.
    $annotation->validate($reflected_parameters)


    This might be the more sensible approach to such an annotation anyway,
    but without any access to variables, I don't really understand the value
    of evaluating an expression for the annotation, just to get a constant
    value that is cached by the Reflection infrastructure.

    If the expression would have to be made up entirely of constants anyway,
    might the same "constant expressions" used in class const definitions be
    a better fit than "any valid PHP expression" - plus a specific exception
    for creating objects out of those constant expressions.

    Regards,
    --
    Rowan Collins
    [IMSoP]
  • Larry Garfield at May 17, 2016 at 4:05 pm

    On 05/17/2016 04:22 PM, Rasmus Schultz wrote:
    I'd like to finish this RFC, but I have two remaining issues.

    The syntax is a minor issue - since any valid PHP expression can be
    used, the bit-shift ambiguity is technically an issue, however
    marginal.

    A lot of people commented on the syntax when I posted the RFC on
    reddit - they don't like it.

    Anyone have any ideas for an alternative syntax? It needs to be
    delimited, e.g. needs to use opening and closing delimiters or a
    recognizable opening delimiter... Here's some ideas:

    @{ new Table("user") }

    @[ new Table("user") ]

    {{ new Table("user") }}

    +{ new Table("user") }

    I don't like any of these really, but the bit-shift operator isn't
    going when the stuff inside is an expression which could include
    bit-shift (is it?)

    The other issue is the dependency (context) injection example - no one
    seems to be able to cite an actual use-case, and if that's the case, I
    should probably just remove it from the RFC entirely?

    @Larry can you think of a case example in the myriad annotations
    you've seen in Drupal code? :-)
    That's on my todo list for later this week. :-) I'm recently arrived in
    Paris so jetlagged beyond coherent thought at the moment, but I will see
    what I can do on a Drupal case study.

    --Larry Garfield
  • Guilhermeblanco at May 17, 2016 at 4:22 pm
    @Rasmus: This approach is too broad, allowing situations like Marco pointed
    out. I'd have to vote -1 on it too if you move forward, specially if you
    consider things like << "How do I grab this?" >> and other weirdness.


    @Rowan: Annotations should be immutable by nature. Still, I would love if
    you can detail (in the context of your example) what should be the output
    in the following examples:

    <<ValidateRange($percentage, 0, 100)>>
    function foo(int $percentage) {
         $reflection = new \ReflectionFunction(__FUNCTION__);

         var_dump($reflection->getAnnotations()); // #2
    }


    $reflection = new \ReflectionFunction("foo");

    var_dump($reflection->getAnnotations()); // #1

    foo(10);

    When executing the code, what should I expect from #1 and #2? I can foresee
    that #1 should crash (?) or should it return an ast\node or what?
    It all sounds reasonable on #2 what everyone is heavily forcing/suggesting
    because of DbC, but it *only* makes sense in the context of a function call
    (or a bound object in case of OO members). In any other case its outcome is
    unpredictable.




    There're 2 potential approaches I can foresee with future for Annotations:

    1- This one I see as a simple approach. Take the idea of Dmitry and extend
    to support scalars and arrays (only, no objects, no AST\Nodes). Example: <<
    Entity(["name" => "User"]) >>
    Strings could be easily converted into AST\Nodes internally and DbC would
    be possible. Context is inferred at libraries' desire.
    Solution here would not have a 1-1 dependency with classes, simplifying the
    implementation for meta parameters such as "override", "inherit",
    "memoize", "jit", etc.

    2- Take an OO approach and correlate 1-1 class. But before that I'd tackle
    object initialization first. We'd require to make this to work:

    new Foo() {
         "property" => "value"
    }

    After that, we could get back to Annotations and support a subset of PHP
    grammar, similar to this:

    << Foo { "property" => "value" } >>


    Why I suggest this approach, some may ask? Simple young padawans... We're
    already seeing people discuss about final/read-only properties, where they
    could only be set at constructor time. We could easily expose this
    possibility through scopes. The {} block would be post constructor, but
    still in the initialization context, allowing sets to happen for read-only
    properties. It's a smart solution against adding a long list of constructor
    arguments (and handling default values for each one) and also a nice
    alternative to "named parameters".
    However, this approach would still require a 1-1 dependency with classes,
    which would make "override", "inherit", "jit" a PITA, and likely empower a
    more robust annotation solution (like defining which class can be an
    annotation and what cannot, or specify annotation target, like class,
    method, property, etc).


    PS: I hate to write long emails... =(

    Cheers,
    On Tue, May 17, 2016 at 11:28 AM, Rowan Collins wrote:
    On 17/05/2016 15:22, Rasmus Schultz wrote:

    The other issue is the dependency (context) injection example - no one
    seems to be able to cite an actual use-case, and if that's the case, I
    should probably just remove it from the RFC entirely?

    @Larry can you think of a case example in the myriad annotations
    you've seen in Drupal code? :-)

    Anyone else using Doctrine Annotations actually seen anyone making use
    of a closure in an annotation?
    Possibly nobody's responded to your call for an example because they're
    not sure what it is you're asking for an example of. I don't really
    understand what closures have to do with annotations, or how that relates
    to capturing context.

    An example from the other thread of a context-bound annotation would be
    implementing validation like this:

    <<ValidateRange($percentage, 0, 100)>>
    function foo(int $percentage)


    This would appear to be unsupported as such by your proposal, so you would
    instead just have to use strings to represent how it needed to be accessed:

    <<new ValidateRangeAnnotation('$percentage', 0, 100)>>

    and then have extra machinery in the reflection logic to extract the
    parameters and pass them to the object, e.g.
    $annotation->validate($reflected_parameters)


    This might be the more sensible approach to such an annotation anyway, but
    without any access to variables, I don't really understand the value of
    evaluating an expression for the annotation, just to get a constant value
    that is cached by the Reflection infrastructure.

    If the expression would have to be made up entirely of constants anyway,
    might the same "constant expressions" used in class const definitions be a
    better fit than "any valid PHP expression" - plus a specific exception for
    creating objects out of those constant expressions.

    Regards,
    --
    Rowan Collins
    [IMSoP]

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

    --
    Guilherme Blanco
    Lead Architect at E-Block
  • Rowan Collins at May 17, 2016 at 4:40 pm

    On 17/05/2016 17:21, guilhermeblanco@gmail.com wrote:
    It all sounds reasonable on #2 what everyone is heavily
    forcing/suggesting because of DbC, but it *only* makes sense in the
    context of a function call (or a bound object in case of OO members). In
    any other case its outcome is unpredictable.
    Yeah, you're right, access to an actual parameter value or runtime
    instance requires logic somewhere else to provide the context, and to
    run the check on every execution of a function requires some magic to
    inject it into the call stack, or the function body, so my example
    doesn't really make any sense.

    Regards,
    --
    Rowan Collins
    [IMSoP]
  • Fleshgrinder at May 17, 2016 at 5:04 pm

    On 5/17/2016 11:06 AM, Rasmus Schultz wrote:
    I believe I have already stated my position on all of these concerns
    in my last email.
    Sorry if I cannot keep everything in my mind.
    On 5/17/2016 11:06 AM, Rasmus Schultz wrote:
    There's no such thing as optional dependencies - if you depend on a
    Doctrine ORM annotation, you depend on that package.
    Both statements are not true.

    #1
    A good example of an optional dependency can be found in the Symfony
    console package:

    https://github.com/symfony/console/blob/master/composer.json#L28
    https://github.com/symfony/console/blob/master/Application.php#L814-L816

    #2
    I could have code in a third-party package that provides some default
    annotations which suggests me to install some annotation systems that
    are capable of handling exactly those annotations. However, I decide to
    only use one of the suggested annotation systems in my project. With
    your solution this is not possible because it always ends up in fatal
    errors; although I consciously decided to not install one suggested
    dependency. See #1 for such an example.

    The only solution for the maintainer of the third-party package would be
    to provide multiple versions of the same package:

    1. No annotations.
    2. Annotations from System X.
    3. Annotations from System Y.
    4. Annotations from System X and Y.
    5. ...

    This is not an acceptable approach.
    On 5/17/2016 11:06 AM, Rasmus Schultz wrote:
    The code should (must) error the moment you try to instantiate those
    annotations - whether you intend to use them or not is besides the
    question - a missing class is an error, in annotations as it is
    anywhere else in your code.
    It is not (again see #1) a problem at compile time and always at
    runtime. You can try this easily on your console:

       $ php -r 'if (false) { new NonExistingClass; }'
       $ php -r 'if (true) { new NonExistingClass; }'
       Fatal error: Uncaught Error: Class 'NonExistingClass' not found in
    Command line code:1
       Stack trace:
       #0 {main}
         thrown in Command line code on line 1
    On 5/17/2016 11:06 AM, Rasmus Schultz wrote:
    Silently ignoring missing annotations solves nothing - it just leads
    to errors that are even harder to find and debug.
    My proposal errors as soon as you try to retrieve an annotation with the
    annotation reader which was not previously registered as such. However,
    you can use Reflection and introspect any existing annotation without
    any kind of error.

    That is how it should be!
    On 5/17/2016 11:06 AM, Rasmus Schultz wrote:
    You seem awfully concerned about name collisions?
    No, I am not. It is just a nice side product of my proposal.
    On 5/17/2016 11:06 AM, Rasmus Schultz wrote:
    The one new thing you brought up here, is the issue of potentially
    loading/instantiating a bunch of annotations that go unused. [...]
    From a performance point of view [...]
    The problem is parsing and interpreting them although they might not be
    used because the current path of logic will not go through them at all.
    This is not a micro optimization thing. You just don't want to interact
    with annotations at all until they are actually needed. This is true for
    any kind of PHP code.

    See console commands above.
    On 5/17/2016 11:06 AM, Rasmus Schultz wrote:
    The extreme case of what you're proposing, is what Go does - an
    annotation is simply a string. No chance of any error, anywhere, ever,
    right? Wrong. People put JSON data in those strings for example, and
    parsing that data leads to run-time errors instead. That's the extreme
    example, but the problem with what you're proposing is precisely the
    same: you allow something like nested array data structures, those are
    still going to get interpreted and mapped to objects at run-time, and
    it leads to run-time errors instead.
    Runtime errors for a runtime feature, well, yes. Again, see console
    command example above.

       @someAnnotation('{"json": "data"}') function f();
       @someAnnotation('invalid json') function x();

       $reflector = new ReflectionFunction('f');
       $annotations = $reflector->getAnnotations();
       /*
       $annotations = [
         'someAnnotation' => [
           ['{"json": "data"}'],
         ],
       ];
       */

       $reflector = new ReflectionFunction('x');
       $annotations = $reflector->getAnnotations();
       /*
       $annotations = [
         'someAnnotation' => [
           ['invalid json'],
         ],
       ];
       */

       annotation_register('someAnnotation', function (string $json) {
         $decoded_json = json_decode($json);
         if ($decoded_json === false) {
           throw new JsonParseException(json_last_error_msg());
         }
         return $decoded_json;
       });

       $annotations = new AnnotatedFunction('f');
       $some_annotations = $annotations->getAnnotations('someAnnotations');
       echo $some_annotations[0]->json;
       // data

       $annotations = new AnnotatedFunction('x');
       $some_annotations = $annotations->getAnnotations('someAnnotations');
       // Fatal error: Uncaught JsonParseException in ...

    The above is just fine. The annotation library registered the callback
    and it knows what kind of errors can happen. The annotation library is
    also the one reading the annotations and it can therefore easily handle
    those errors and act upon them. Of course in the above case the fatal
    error is just fine and it is the developers duty to write unit tests and
    take care of writing proper configuration. It is not PHP's duty to
    ensure to absolutely no error can happen in any subsystem. (This is
    actually ridiculous to think of in the first place.)
    On 5/17/2016 11:06 AM, Rasmus Schultz wrote:
    I maintain that the majority use-case is object annotations - and that
    deferring the construction of those objects doesn't solve anything.
    Seriously? Every construction is deferred, always, again see the console
    example from above.
    On 5/17/2016 11:06 AM, Rasmus Schultz wrote:
    You're just deferring or hiding the problem, adding complexity, and
    mental as well as practical debugging effort - but the problem doesn't
    go away.
    I am putting a runtime feature to runtime like all runtime features are
    at runtime in PHP. The error is hidden during reflection, that is true,
    but on purpose! You do not want reflection to error out while you are
    performing introspection on a data structure.

    The annotation reader however will error out in the moment you try to
    access something. This separation of concern makes it actually easier
    and is in the vain of good software development too.

    I understand what you want to solve. I am just telling you that this is
    the wrong approach and others are telling it to you too.

    --
    Richard "Fleshgrinder" Fussenegger
  • Rasmus Schultz at May 17, 2016 at 5:47 pm
    I don't really understand what closures have to do with annotations, or how that relates to capturing context.
    The point is that, rather than trying to capture context, you can just
    as well ask for what you need.

    I'm going to use a very contrived example, because I really can't
    think of any real case that requires context:

    class User
    {
         << new Validation(function ($value) { return false !==
    filter_var($value, FILTER_VALIDATE_EMAIL); }) >>
         public $email;
    }

    Like I said, extremely contrived - in practice, you wouldn't need to
    attach functionality in that way.
    An example from the other thread of a context-bound annotation would be implementing validation like this
    You're not annotating the function - this is just a round-about way of
    annotating the argument.

    You would do that directly, like this:

    function foo(
         << ValidateRange(0, 100) >>
         int $percentage
    ) { ... }
    If the expression would have to be made up entirely of constants anyway, might the same "constant expressions" used in class const definitions be a better fit than "any valid PHP expression" - plus a specific exception for creating objects out of those constant expressions.
    Probably not - what happens with what is today "nested annotations"
    then? Or will you make an exception for those too?

    The problem is, you're just reinventing a subset of the programming
    language, and I'm sure you can keep expanding on that indefinitely.
    What for? Just use the facilities already defined by the language.

    This fear of any feature that lets you do "evil" is incomprehensible
    to me. Most features of almost any programming language can be used
    for "evil". IMO, the real question is whether a feature accomplishes
    what you want. If you insist on something that also prevents things
    you don't want, you're bound to end up with something a lot more
    complex that fits into the language a lot less naturally...

    On Tue, May 17, 2016 at 5:28 PM, Rowan Collins wrote:
    On 17/05/2016 15:22, Rasmus Schultz wrote:

    The other issue is the dependency (context) injection example - no one
    seems to be able to cite an actual use-case, and if that's the case, I
    should probably just remove it from the RFC entirely?

    @Larry can you think of a case example in the myriad annotations
    you've seen in Drupal code? :-)

    Anyone else using Doctrine Annotations actually seen anyone making use
    of a closure in an annotation?

    Possibly nobody's responded to your call for an example because they're not
    sure what it is you're asking for an example of. I don't really understand
    what closures have to do with annotations, or how that relates to capturing
    context.

    An example from the other thread of a context-bound annotation would be
    implementing validation like this:

    <<ValidateRange($percentage, 0, 100)>>
    function foo(int $percentage)


    This would appear to be unsupported as such by your proposal, so you would
    instead just have to use strings to represent how it needed to be accessed:

    <<new ValidateRangeAnnotation('$percentage', 0, 100)>>

    and then have extra machinery in the reflection logic to extract the
    parameters and pass them to the object, e.g.
    $annotation->validate($reflected_parameters)


    This might be the more sensible approach to such an annotation anyway, but
    without any access to variables, I don't really understand the value of
    evaluating an expression for the annotation, just to get a constant value
    that is cached by the Reflection infrastructure.

    If the expression would have to be made up entirely of constants anyway,
    might the same "constant expressions" used in class const definitions be a
    better fit than "any valid PHP expression" - plus a specific exception for
    creating objects out of those constant expressions.


    Regards,
    --
    Rowan Collins
    [IMSoP]

    --
    PHP Internals - PHP Runtime Development Mailing List
    To unsubscribe, visit: http://www.php.net/unsub.php
  • Fleshgrinder at May 17, 2016 at 6:01 pm

    On 5/17/2016 7:47 PM, Rasmus Schultz wrote:
    You're not annotating the function - this is just a round-about way of
    annotating the argument.

    You would do that directly, like this:

    function foo(
    << ValidateRange(0, 100) >>
    int $percentage
    ) { ... }
    What is this good for?
    When is /ValidateRange/ being evaluated?
    On every call? How?

    I really do not get it, sorry.

    --
    Richard "Fleshgrinder" Fussenegger
  • Rowan Collins at May 17, 2016 at 6:39 pm

    On 17/05/2016 18:47, Rasmus Schultz wrote:
    I don't really understand what closures have to do with annotations, or how that relates to capturing context.
    The point is that, rather than trying to capture context, you can just
    as well ask for what you need.

    I'm going to use a very contrived example, because I really can't
    think of any real case that requires context:

    class User
    {
    << new Validation(function ($value) { return false !==
    filter_var($value, FILTER_VALIDATE_EMAIL); }) >>
    public $email;
    }

    Like I said, extremely contrived - in practice, you wouldn't need to
    attach functionality in that way.
    Right, in my mind this is less about *context*, and more about *passing
    code into the implementation*. I think we agree that an implementation
    of validation-by-annotation would look something like:

    $validators = $reflected_thing->getAnnotations('someFilter');
    foreach ( $validators as $validator ) {
    $validator->validate($some_instance);
    }

    This gets its *context* from the code running the validator; the
    implementation of the validate() method would normally just be part of
    the annotation type:

    <<new RangeValidator(1, 100)>>
    var $foo;


    The closure example you gave would be a way of providing on-the-fly
    dynamic *behaviour* as the argument to an annotation. This wouldn't
    really make sense for validation (a custom validator would still
    probably be defined once and used for several fields, but theoretically
    you could have:

    <<new CustomValidator(function($value){ return is_prime($value); })>>

    It's not the context that's magic here, it's the ability to specify code
    as part of the annotation *value*, rather than the annotation *definition*.


    A more obvious example therefore is using annotations to implement DbC:

    <<new Precondition(function($values) { ... })>>

    Although as I admitted to Guilherme, that requires some magic to run it
    at the right time anyway...

    An example from the other thread of a context-bound annotation would be implementing validation like this
    You're not annotating the function - this is just a round-about way of
    annotating the argument.

    You would do that directly, like this:

    function foo(
    << ValidateRange(0, 100) >>
    int $percentage
    ) { ... }
    Sure, but it's easy to come up with a variant that requires access to
    more than one parameter, say:

    << ValidateLessThan($min, $max) >>
    function foo($min, $max)

    Which without any context or AST would need to be either:

    << ValidateLessThan('$min', '$max') >>
    function foo($min, $max)

    ...which rather defeats the point of having code rather than just a string.

    Or:

    << ValidateCustom(function($min, $max) { return $min < $max } >>
    function foo($min, $max)

    ...which feels rather clunky.

    If the expression would have to be made up entirely of constants anyway, might the same "constant expressions" used in class const definitions be a better fit than "any valid PHP expression" - plus a specific exception for creating objects out of those constant expressions.
    Probably not - what happens with what is today "nested annotations"
    then? Or will you make an exception for those too?
    How would you "nest" annotations in your scheme anyway? As far as I can
    see, they would be either multi-level arrays (a valid constant
    expression) or nested constructor calls. So there's still exactly one
    exception made, the "new Foo(args)" construct.

    The problem is, you're just reinventing a subset of the programming
    language, and I'm sure you can keep expanding on that indefinitely.
    What for? Just use the facilities already defined by the language.
    That's a fair point. The flipside is that the more things you allow the
    user to do, the more edge cases you have to deal with when evaluating
    the expressions in your special "zero context".

    This fear of any feature that lets you do "evil" is incomprehensible
    to me. Most features of almost any programming language can be used
    for "evil".
    I am not suggesting removing the ability to avoid people doing evil; I'm
    suggesting that the feature you call "simple annotations" could be a lot
    simpler.

    What is the value of being able to write this:

    function foo() { return 'MyAnnotation'; }

    << foo() >>
    class A {}

    When you could just write this:

    << 'MyAnnotation' >>

    IMO, the real question is whether a feature accomplishes
    what you want. If you insist on something that also prevents things
    you don't want, you're bound to end up with something a lot more
    complex that fits into the language a lot less naturally...
    In my mind, something that lets me evaluate an arbitrary expression in
    some weird null-context, at an unspecified time (because I don't know
    what code will be the first to request that annotation), only to have
    the result stored in some invisible static variable, is *more* complex
    than many of the alternatives.

    Regards,
    --
    Rowan Collins
    [IMSoP]

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupphp-internals @
categoriesphp
postedMay 13, '16 at 12:11p
activeMay 17, '16 at 6:39p
posts25
users10
websitephp.net

People

Translate

site design / logo © 2018 Grokbase