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.
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.
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.
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:
<<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.
--
--Larry Garfield
On Thu, Apr 21, 2016 at 11:52 PM, Larry Garfield larry@garfieldtech.com
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, etchttps://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
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, etchttps://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.)
Makes sense. I may change this.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.)
I'm not sure yet. both decisions may make sense. If I expect just a
single value, I'll have to check the number of elements (or just ignore
values above the first).
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?
This is just an AST. It may contain any valid PHP expression syntax, but
variable, functions and constants don't have to be valid.
How can I evaluate test?
I hope this functionality will be provided by php-ast extension.
Currently, it is not a problem to reconstruct PHP source from AST and
then use regular eval().
In general, we may find a more efficient way.
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.
AST is going to be mainly used by extension and pre-processors (like AOT
and DBC), but in general, they also may be used directly in scripts.
<<test($a + $b > 0)>>
function foo($a, $b) {
ast_eval(RefelectionFunction(FUNCTION)->getAttributes()["test"]);
}
DB
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.
yeah, computers think they are too smart :)
If I read correctly, the following two would be semantically identical:
<<One, Two>>
function foo() {}<<One>>
<<Two>>
function foo() {}
right
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?
I took the name from HHVM. Personally, I don't care about naming at all.
It appears that the annotations themselves are entirely free-form.
no. they are parsed according to PHP expression syntax rules. syntax
mistakes in attributes are going to be caught at compile time.
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.
This is just a next level. Attributes are just a storage of meta-data.
You may use them as you like :)
function getAttributesAsObjects($r) {
$ret = array();
$a = $r->getAttributes();
foreach ($a as $name => $val) {
$ret[] = new $name(...$val);
}
return $ret;
}
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:<<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.
We can't use classes and object in storage directly, because they may be
defined in different PHP script, may be changed between requests, etc.
but as I showed, it's very easy to construct corresponding objects on
request.
Thanks for deep review and good suggestions.
Dmitry.
This is amazing. It would actually allow us to implement our automated
assertions ourselves, as opposed to requiring it within the language.
Could it also support references?
<<sanitize(&$a)>>
function foo($a) {
}
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, etchttps://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.
This is amazing. It would actually allow us to implement our
automated assertions ourselves, as opposed to requiring it within the
language.
this was the idea - to give a good tool instead of implementing every
possible use-case in the language.
Could it also support references?
<<sanitize(&$a)>>
function foo($a) {}
yes. "&$a" is a valid PHP expression.
If you plan to use this, I would appreciate, if you to build the patched
PHP and try it.
The early we find problems the better feature we will get at the end.
Thanks. Dmitry.
On 21 Apr 2016 10:13 p.m., "Dmitry Stogov" <dmitry@zend.com
mailto:dmitry@zend.com> 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.
As a previous suggester of metadata information built-in into PHP, and also
one of developers of the most used metadata library written in PHP, I
understand this feature implementation requires several design decisions
and also a good understanding of specific situations users may require.
While I am a strong supporter of a more robust solution, this is already a
good start.
A few things I'd like to ask for my own understanding and also suggestions
too:
1- I understand you took a minimalistic approach towards a "dumb"
implementation for attributes (when I mean "dumb", the idea here is towards
a non-OO approach). Can you explain your motivations towards this approach?
I see two distinct approaches of implementation for this feature. Both of
them have some common demands, like lazy initialization of metadata. Here
they are:
- Simplistic approach, which lets consumers of the feature do all the work
related to validation, assertion of valid keys, values, etc
This does not invalidate the ability to leverage of some features that a
more robust implementation demands.
- Robust approach: language takes the burden of instantiating complex
structures, validating, assertion of valid keys, values, if this complex
structure is allowed to be instantiated in that given class, method, etc.
1- Your approach is basically defining an array. Could you explain your
line of thinking on why you didn't consider a syntax like the one below?
<["key" => "value"]>
class Foo {}
2- I see that you added support over functions, classes, constants and
properties. According to the RFC, getAttributes() was added over
ReflectionFunction. Is there a reason why support was not added to methods
(ReflectionMethod extends ReflectionFunctionAbstract, which was not
mentioned on RFC)? Any reason to not support it in function/method
parameters?
3- Did you put any thought on inheritance? What I mentioned in comment #1
is even smaller than what you implemented in RFC.
Assuming you keep the RFC approach, did you consider support overrides,
inherit, etc?
4- I understand that a more robust attribute solution would be required to
achieve this, but one of the biggest advantages of AOP is the ability to
perform custom logic before, after or around... However, I don't know if
any kind of triggers came in your head or are planned as a future RFC.
Let me highlight one example: Every time a class, property or method is
called that is annotated as <
`E_USER_DEPRECATED` warning. A trigger-like solution would be required. Did
this concept came to your mind?
Regards,
>
>
>
>
>>
>> This is amazing. It would actually allow us to implement our automated
>> assertions ourselves, as opposed to requiring it within the language.
>>
>> this was the idea - to give a good tool instead of implementing every
> possible use-case in the language.
>
> Could it also support references?
>>
>> <
>> function foo($a) {
>>
>> }
>>
>> yes. "&$a" is a valid PHP expression.
>
> If you plan to use this, I would appreciate, if you to build the patched
> PHP and try it.
> The early we find problems the better feature we will get at the end.
>
> Thanks. Dmitry.
>
>
> On 21 Apr 2016 10:13 p.m., "Dmitry Stogov"
>>
>> 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.
>>
>>
>
--
Guilherme Blanco
Lead Architect at E-Block
Hi Dmitry,
As a previous suggester of metadata information built-in into PHP, and
also one of developers of the most used metadata library written in
PHP, I understand this feature implementation requires several design
decisions and also a good understanding of specific situations users
may require.While I am a strong supporter of a more robust solution, this is
already a good start.
A few things I'd like to ask for my own understanding and also
suggestions too:1- I understand you took a minimalistic approach towards a "dumb"
implementation for attributes (when I mean "dumb", the idea here is
towards a non-OO approach). Can you explain your motivations towards
this approach?I see two distinct approaches of implementation for this feature. Both
of them have some common demands, like lazy initialization of
metadata. Here they are:
Simplistic approach, which lets consumers of the feature do all the
work related to validation, assertion of valid keys, values, etc
This does not invalidate the ability to leverage of some features that
a more robust implementation demands.Robust approach: language takes the burden of instantiating complex
structures, validating, assertion of valid keys, values, if this
complex structure is allowed to be instantiated in that given class,
method, etc.
I didn't exactly understand what do you suggest.
If you are talking about Attribute objects initialization during
compilation - this is just not possible from implementation point of view.
Now attributes may be stored in opcache SHM and relive request boundary.
Objects can't relive requests.
1- Your approach is basically defining an array. Could you explain
your line of thinking on why you didn't consider a syntax like the one
below?<["key" => "value"]>
class Foo {}
I didn't try to invite new syntax. Just completely took it from HHVM.
2- I see that you added support over functions, classes, constants and
properties. According to the RFC, getAttributes() was added over
ReflectionFunction. Is there a reason why support was not added to
methods (ReflectionMethod extends ReflectionFunctionAbstract, which
was not mentioned on RFC)? Any reason to not support it in
function/method parameters?
ReflectionMethod is a child of ReflectinFunction, so it's supported.
Attributes are allowed for the same entities as doc-comments (they are
not allowed for parameters)
3- Did you put any thought on inheritance? What I mentioned in comment
#1 is even smaller than what you implemented in RFC.
Assuming you keep the RFC approach, did you consider support
overrides, inherit, etc?
In my opinion, attributes don't have to be inherited.
If you think differently - please explain your point.
4- I understand that a more robust attribute solution would be
required to achieve this, but one of the biggest advantages of AOP is
the ability to perform custom logic before, after or around...
However, I don't know if any kind of triggers came in your head or are
planned as a future RFC.
Let me highlight one example: Every time a class, property or method
is called that is annotated as <<deprecated>>, I would like to issue
anE_USER_DEPRECATED
warning. A trigger-like solution would be
required. Did this concept came to your mind?
This is not a subject of this RFC.
Attributes provides a storage for metadata, but don't define how to use
them.
Especially, for your use-case:
- it's possible to create preprocessor that embeds corresponding
trigger_error()
call - it's possible to write a PHP extension that plugs-into compiler chain
and checks <<deprecated>> attribute for each compiles function, then
sets ZEND_ACC_DEPRECATED flag - It's also possible to override DO_FCALL opcodes and perform checks
there (this is inefficient)
Thanks. Dmitry.
Regards,
On Thu, Apr 21, 2016 at 7:44 PM, Dmitry Stogov <dmitry@zend.com
mailto:dmitry@zend.com> wrote:This is amazing. It would actually allow us to implement our automated assertions ourselves, as opposed to requiring it within the language. this was the idea - to give a good tool instead of implementing every possible use-case in the language. Could it also support references? <<sanitize(&$a)>> function foo($a) { } yes. "&$a" is a valid PHP expression. If you plan to use this, I would appreciate, if you to build the patched PHP and try it. The early we find problems the better feature we will get at the end. Thanks. Dmitry. On 21 Apr 2016 10:13 p.m., "Dmitry Stogov" <dmitry@zend.com <mailto:dmitry@zend.com> <mailto:dmitry@zend.com <mailto:dmitry@zend.com>>> 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.
--
Guilherme Blanco
Lead Architect at E-Block
>
>
>
>
> Hi Dmitry,
>
> As a previous suggester of metadata information built-in into PHP, and
> also one of developers of the most used metadata library written in PHP, I
> understand this feature implementation requires several design decisions
> and also a good understanding of specific situations users may require.
>
> While I am a strong supporter of a more robust solution, this is already a
> good start.
> A few things I'd like to ask for my own understanding and also suggestions
> too:
>
> 1- I understand you took a minimalistic approach towards a "dumb"
> implementation for attributes (when I mean "dumb", the idea here is towards
> a non-OO approach). Can you explain your motivations towards this approach?
>
> I see two distinct approaches of implementation for this feature. Both of
> them have some common demands, like lazy initialization of metadata. Here
> they are:
>
> - Simplistic approach, which lets consumers of the feature do all the work
> related to validation, assertion of valid keys, values, etc
> This does not invalidate the ability to leverage of some features that a
> more robust implementation demands.
>
> - Robust approach: language takes the burden of instantiating complex
> structures, validating, assertion of valid keys, values, if this complex
> structure is allowed to be instantiated in that given class, method, etc.
>
>
> I didn't exactly understand what do you suggest.
> If you are talking about Attribute objects initialization during
> compilation - this is just not possible from implementation point of view.
> Now attributes may be stored in opcache SHM and relive request boundary.
> Objects can't relive requests.
>
I know that object instances are not cross-requests. Explicitly, I
mentioned that both approaches require lazy-initialization (which means,
whenever you call getAttributes() or getAttribute()).
What I mentioning is that your approach is basically a new key/value syntax
that are used specifically for Attributes. We could easily turn this into a
more robust approach if instead of defining key/value pairs, we instantiate
objects or call functions. You already demonstrated interest to support
<
Doctrine Annotations), so why not issue constructor or function calls
there? That would simplify the work needed for consumers and also add room
for later improvements.
So basically in this example:
use Doctrine\ORM;
<
class User {}
$reflClass = new \ReflectionClass("User");
var_dump($reflClass->getAttributes());
We'd be changing from this:
array(1) {
["Doctrine\ORM\Entity"]=>
array(1) {
[0]=>
string(4) "user"
}
}
Into this:
array(1) {
["Doctrine\ORM\Entity"]=>
object(Doctrine\ORM\Entity)#1 (1) {
["tableName"]=>
string(4) "user"
}
}
>
> 1- Your approach is basically defining an array. Could you explain your
> line of thinking on why you didn't consider a syntax like the one below?
>
> <["key" => "value"]>
> class Foo {}
>
> I didn't try to invite new syntax. Just completely took it from HHVM.
>
My idea was based on your current proposal, which is basically a way to
define key/value pairs.
If you decide to go minimalistic, that is probably my best line of thinking.
>
>
>
> 2- I see that you added support over functions, classes, constants and
> properties. According to the RFC, getAttributes() was added over
> ReflectionFunction. Is there a reason why support was not added to methods
> (ReflectionMethod extends ReflectionFunctionAbstract, which was not
> mentioned on RFC)? Any reason to not support it in function/method
> parameters?
>
> ReflectionMethod is a child of ReflectinFunction, so it's supported.
>
Attributes are allowed for the same entities as doc-comments (they are not
> allowed for parameters)
>
I was asking if there was a purpose to not support Attributes over
ReflectionParameter. Example:
class Foo {
public function bar(<
// ...
}
}
$reflClass = new \ReflectionClas("Foo");
$reflMethod = $reflClass->getMethod("bar");
$reflParameter = $reflMethod->getParameters()[0];
var_dump($reflParameter->getAttributes());
>
>
>
> 3- Did you put any thought on inheritance? What I mentioned in comment #1
> is even smaller than what you implemented in RFC.
> Assuming you keep the RFC approach, did you consider support overrides,
> inherit, etc?
>
>
> In my opinion, attributes don't have to be inherited.
> If you think differently - please explain your point.
>
Of source I can.
A simple case would be to increate visibility of the inherited property. It
was declared in a parent class as protected, but now you want public, and
you still want to keep all parent defined Attributes.
Another example is like we do in Doctrine. We support a callback system
which we named as lifetime callbacks. Pre-persist is one of them, which is
called every time a given Entity is about to be persisted into DB. When
you're dealing with inheritance, you can potentially override the method
content and you still want to trigger the same operation as if it was
untouched. Example:
use Doctrine\ORM;
trait Timestampable {
protected $created;
protected $updated;
<
public function prePersist() {
$this->created = $this->updated = new \DateTime("now");
}
<
public function preUpdate() {
$this->updated = new \DateTime("now");
}
}
<
class User {
use Timestampable;
public function prePersist() {
// Add my custom logic
}
}
The implication is that through a simplistic approach, inheriting (or
overriding) is not clear and I can't figure it out an easy way to achieve
that.
Now if we go towards calling a function or class constructor like I
mentioned before, then we could easily build structures like __Inherit,
__Override, etc.
>
> 4- I understand that a more robust attribute solution would be required to
> achieve this, but one of the biggest advantages of AOP is the ability to
> perform custom logic before, after or around... However, I don't know if
> any kind of triggers came in your head or are planned as a future RFC.
> Let me highlight one example: Every time a class, property or method is
> called that is annotated as <
> `E_USER_DEPRECATED` warning. A trigger-like solution would be required. Did
> this concept came to your mind?
>
> This is not a subject of this RFC.
> Attributes provides a storage for metadata, but don't define how to use
> them.
> Especially, for your use-case:
> 1) it's possible to create preprocessor that embeds corresponding
> `trigger_error()` call
> 2) it's possible to write a PHP extension that plugs-into compiler chain
> and checks <
> ZEND_ACC_DEPRECATED flag
> 3) It's also possible to override DO_FCALL opcodes and perform checks
> there (this is inefficient)
>
>
With this simplistic approach, I agree there's 0 value into considering
this.
However, taking a more robust approach would potentially open this
possibility through a simpler extension.
> Thanks. Dmitry.
>
>
>
>
>
> Regards,
>
>
>
>>
>>
>>
>>
>>>
>>> This is amazing. It would actually allow us to implement our automated
>>> assertions ourselves, as opposed to requiring it within the language.
>>>
>>> this was the idea - to give a good tool instead of implementing every
>> possible use-case in the language.
>>
>> Could it also support references?
>>>
>>> <
>>> function foo($a) {
>>>
>>> }
>>>
>>> yes. "&$a" is a valid PHP expression.
>>
>> If you plan to use this, I would appreciate, if you to build the patched
>> PHP and try it.
>> The early we find problems the better feature we will get at the end.
>>
>> Thanks. Dmitry.
>>
>>
>> On 21 Apr 2016 10:13 p.m., "Dmitry Stogov" <
>>> dmitry@zend.com
>>>
>>> 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.
>>>
>>>
>>
>
>
> --
> Guilherme Blanco
> Lead Architect at E-Block
>
>
>
--
Guilherme Blanco
Lead Architect at E-Block
3- Did you put any thought on inheritance? What I mentioned in comment #1
is even smaller than what you implemented in RFC.
Assuming you keep the RFC approach, did you consider support overrides,
inherit, etc?In my opinion, attributes don't have to be inherited.
If you think differently - please explain your point.Of source I can.
A simple case would be to increate visibility of the inherited property. It
was declared in a parent class as protected, but now you want public, and
you still want to keep all parent defined Attributes.
Another example is like we do in Doctrine. We support a callback system
which we named as lifetime callbacks. Pre-persist is one of them, which is
called every time a given Entity is about to be persisted into DB. When
you're dealing with inheritance, you can potentially override the method
content and you still want to trigger the same operation as if it was
untouched. Example:use Doctrine\ORM;
trait Timestampable {
protected $created;
protected $updated;<<ORM\PrePersist>> public function prePersist() { $this->created = $this->updated = new \DateTime("now"); } <<ORM\PreUpdate>> public function preUpdate() { $this->updated = new \DateTime("now"); }
}
<<ORM\Entity>>
class User {
use Timestampable;public function prePersist() { // Add my custom logic }
}
The implication is that through a simplistic approach, inheriting (or
overriding) is not clear and I can't figure it out an easy way to achieve
that.
Now if we go towards calling a function or class constructor like I
mentioned before, then we could easily build structures like __Inherit,
__Override, etc.
Here's another example from a Doctrine-using project I built a while
back. (Not the exact code, but the same concept; I've adapted it to PHP
7 types as well):
interface Ownable {
public function getOwner() : string;
public function setOwner(string $u);
public function isUnowned() : bool;
}
trait OwnableTrait {
/** @ORM\String **/
private $owner = '';
public getOwner() : string {
return $this->owner;
}
public setOwner(string $u) {
$this->owner = $owner;
}
public function isUnowned() : bool {
return $this->owner == '';
}
}
/** @ORM\Entity */
class Product implements Ownable {
use OwnableTrait;
// ...
}
class Widget extends Product {
// ...
}
For annotations to work for this use case, reflecting on the properties
of Widget would need to include $owner, and it would need to include the
ORM\String annotation. (True regardless of whether annotations are
array or object based.)
--
--Larry Garfield
3- Did you put any thought on inheritance? What I mentioned in
comment #1
is even smaller than what you implemented in RFC.
Assuming you keep the RFC approach, did you consider support overrides,
inherit, etc?In my opinion, attributes don't have to be inherited.
If you think differently - please explain your point.Of source I can.
A simple case would be to increate visibility of the inherited
property. It
was declared in a parent class as protected, but now you want public,
and
you still want to keep all parent defined Attributes.
Another example is like we do in Doctrine. We support a callback system
which we named as lifetime callbacks. Pre-persist is one of them,
which is
called every time a given Entity is about to be persisted into DB. When
you're dealing with inheritance, you can potentially override the method
content and you still want to trigger the same operation as if it was
untouched. Example:use Doctrine\ORM;
trait Timestampable {
protected $created;
protected $updated;<<ORM\PrePersist>> public function prePersist() { $this->created = $this->updated = new \DateTime("now"); } <<ORM\PreUpdate>> public function preUpdate() { $this->updated = new \DateTime("now"); }
}
<<ORM\Entity>>
class User {
use Timestampable;public function prePersist() { // Add my custom logic }
}
The implication is that through a simplistic approach, inheriting (or
overriding) is not clear and I can't figure it out an easy way to
achieve
that.
Now if we go towards calling a function or class constructor like I
mentioned before, then we could easily build structures like __Inherit,
__Override, etc.Here's another example from a Doctrine-using project I built a while
back. (Not the exact code, but the same concept; I've adapted it to
PHP 7 types as well):interface Ownable {
public function getOwner() : string;
public function setOwner(string $u);
public function isUnowned() : bool;
}trait OwnableTrait {
/** @ORM\String **/
private $owner = '';public getOwner() : string {
return $this->owner;
}public setOwner(string $u) {
$this->owner = $owner;
}public function isUnowned() : bool {
return $this->owner == '';
}
}/** @ORM\Entity */
class Product implements Ownable {
use OwnableTrait;// ...
}class Widget extends Product {
// ...
}For annotations to work for this use case, reflecting on the
properties of Widget would need to include $owner, and it would need
to include the ORM\String annotation. (True regardless of whether
annotations are array or object based.)
In your example you don't override the property, so you'll able to see
attributes of your property.
<?php
trait T {
<<test>>
protected $x;
}
class Foo {
use T;
}
$r = new ReflectionClass("Foo");
$prop = $r->getProperty("x");
var_dump($prop->getAttributes());
?>
$ sapi/cli/php attr7.php
array(1) {
["test"]=>
bool(true)
}
Works fine.
Thanks. Dmitry.
guilhermeblanco@gmail.com> wrote:
>
>
> >
> >
> >
> >
> > Hi Dmitry,
> >
> > As a previous suggester of metadata information built-in into PHP, and
> > also one of developers of the most used metadata library written in PHP,
> I
> > understand this feature implementation requires several design decisions
> > and also a good understanding of specific situations users may require.
> >
> > While I am a strong supporter of a more robust solution, this is already
> a
> > good start.
> > A few things I'd like to ask for my own understanding and also
> suggestions
> > too:
> >
> > 1- I understand you took a minimalistic approach towards a "dumb"
> > implementation for attributes (when I mean "dumb", the idea here is
> towards
> > a non-OO approach). Can you explain your motivations towards this
> approach?
> >
> > I see two distinct approaches of implementation for this feature. Both of
> > them have some common demands, like lazy initialization of metadata. Here
> > they are:
> >
> > - Simplistic approach, which lets consumers of the feature do all the
> work
> > related to validation, assertion of valid keys, values, etc
> > This does not invalidate the ability to leverage of some features that a
> > more robust implementation demands.
> >
> > - Robust approach: language takes the burden of instantiating complex
> > structures, validating, assertion of valid keys, values, if this complex
> > structure is allowed to be instantiated in that given class, method, etc.
> >
> >
> > I didn't exactly understand what do you suggest.
> > If you are talking about Attribute objects initialization during
> > compilation - this is just not possible from implementation point of
> view.
> > Now attributes may be stored in opcache SHM and relive request boundary.
> > Objects can't relive requests.
> >
>
>
> I know that object instances are not cross-requests. Explicitly, I
> mentioned that both approaches require lazy-initialization (which means,
> whenever you call getAttributes() or getAttribute()).
>
> What I mentioning is that your approach is basically a new key/value syntax
> that are used specifically for Attributes. We could easily turn this into a
> more robust approach if instead of defining key/value pairs, we instantiate
> objects or call functions. You already demonstrated interest to support
> <
> Doctrine Annotations), so why not issue constructor or function calls
> there? That would simplify the work needed for consumers and also add room
> for later improvements.
>
> So basically in this example:
>
> use Doctrine\ORM;
>
> <
> class User {}
>
> $reflClass = new \ReflectionClass("User");
> var_dump($reflClass->getAttributes());
>
> We'd be changing from this:
>
> array(1) {
> ["Doctrine\ORM\Entity"]=>
> array(1) {
> [0]=>
> string(4) "user"
> }
> }
>
> Into this:
>
> array(1) {
> ["Doctrine\ORM\Entity"]=>
> object(Doctrine\ORM\Entity)#1 (1) {
> ["tableName"]=>
> string(4) "user"
> }
> }
>
+1
>
>
> >
> > 1- Your approach is basically defining an array. Could you explain your
> > line of thinking on why you didn't consider a syntax like the one below?
> >
> > <["key" => "value"]>
> > class Foo {}
> >
> > I didn't try to invite new syntax. Just completely took it from HHVM.
> >
>
> My idea was based on your current proposal, which is basically a way to
> define key/value pairs.
> If you decide to go minimalistic, that is probably my best line of
> thinking.
>
>
> >
> >
> >
> > 2- I see that you added support over functions, classes, constants and
> > properties. According to the RFC, getAttributes() was added over
> > ReflectionFunction. Is there a reason why support was not added to
> methods
> > (ReflectionMethod extends ReflectionFunctionAbstract, which was not
> > mentioned on RFC)? Any reason to not support it in function/method
> > parameters?
> >
> > ReflectionMethod is a child of ReflectinFunction, so it's supported.
> >
> Attributes are allowed for the same entities as doc-comments (they are not
> > allowed for parameters)
> >
>
> I was asking if there was a purpose to not support Attributes over
> ReflectionParameter. Example:
>
> class Foo {
> public function bar(<
> // ...
> }
> }
>
> $reflClass = new \ReflectionClas("Foo");
> $reflMethod = $reflClass->getMethod("bar");
> $reflParameter = $reflMethod->getParameters()[0];
>
> var_dump($reflParameter->getAttributes());
>
>
> >
> >
> >
> > 3- Did you put any thought on inheritance? What I mentioned in comment #1
> > is even smaller than what you implemented in RFC.
> > Assuming you keep the RFC approach, did you consider support overrides,
> > inherit, etc?
> >
> >
> > In my opinion, attributes don't have to be inherited.
> > If you think differently - please explain your point.
> >
>
> Of source I can.
> A simple case would be to increate visibility of the inherited property. It
> was declared in a parent class as protected, but now you want public, and
> you still want to keep all parent defined Attributes.
> Another example is like we do in Doctrine. We support a callback system
> which we named as lifetime callbacks. Pre-persist is one of them, which is
> called every time a given Entity is about to be persisted into DB. When
> you're dealing with inheritance, you can potentially override the method
> content and you still want to trigger the same operation as if it was
> untouched. Example:
>
> use Doctrine\ORM;
>
> trait Timestampable {
> protected $created;
> protected $updated;
>
> <
> public function prePersist() {
> $this->created = $this->updated = new \DateTime("now");
> }
>
> <
> public function preUpdate() {
> $this->updated = new \DateTime("now");
> }
> }
>
> <
> class User {
> use Timestampable;
>
> public function prePersist() {
> // Add my custom logic
> }
> }
>
> The implication is that through a simplistic approach, inheriting (or
> overriding) is not clear and I can't figure it out an easy way to achieve
> that.
> Now if we go towards calling a function or class constructor like I
> mentioned before, then we could easily build structures like __Inherit,
> __Override, etc.
>
>
> >
> > 4- I understand that a more robust attribute solution would be required
> to
> > achieve this, but one of the biggest advantages of AOP is the ability to
> > perform custom logic before, after or around... However, I don't know if
> > any kind of triggers came in your head or are planned as a future RFC.
> > Let me highlight one example: Every time a class, property or method is
> > called that is annotated as <
> > `E_USER_DEPRECATED` warning. A trigger-like solution would be required. Did
> > this concept came to your mind?
> >
> > This is not a subject of this RFC.
> > Attributes provides a storage for metadata, but don't define how to use
> > them.
> > Especially, for your use-case:
> > 1) it's possible to create preprocessor that embeds corresponding
> > `trigger_error()` call
> > 2) it's possible to write a PHP extension that plugs-into compiler chain
> > and checks <
> > ZEND_ACC_DEPRECATED flag
> > 3) It's also possible to override DO_FCALL opcodes and perform checks
> > there (this is inefficient)
> >
> >
> With this simplistic approach, I agree there's 0 value into considering
> this.
> However, taking a more robust approach would potentially open this
> possibility through a simpler extension.
>
>
>
> > Thanks. Dmitry.
> >
> >
> >
> >
> >
> > Regards,
> >
> >
> >
> >>
> >>
> >>
> >>
> >>>
> >>> This is amazing. It would actually allow us to implement our automated
> >>> assertions ourselves, as opposed to requiring it within the language.
> >>>
> >>> this was the idea - to give a good tool instead of implementing every
> >> possible use-case in the language.
> >>
> >> Could it also support references?
> >>>
> >>> <
> >>> function foo($a) {
> >>>
> >>> }
> >>>
> >>> yes. "&$a" is a valid PHP expression.
> >>
> >> If you plan to use this, I would appreciate, if you to build the patched
> >> PHP and try it.
> >> The early we find problems the better feature we will get at the end.
> >>
> >> Thanks. Dmitry.
> >>
> >>
> >> On 21 Apr 2016 10:13 p.m., "Dmitry Stogov" <
> >>> dmitry@zend.com
> >>>
> >>> 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.
> >>>
> >>>
> >>
> >
> >
> > --
> > Guilherme Blanco
> > Lead Architect at E-Block
> >
> >
> >
>
>
> --
> Guilherme Blanco
> Lead Architect at E-Block
On Fri, Apr 22, 2016 at 3:07 AM, Dmitry Stogov <dmitry@zend.com
mailto:dmitry@zend.com> wrote:On 04/22/2016 04:05 AM, guilhermeblanco@gmail.com <mailto:guilhermeblanco@gmail.com> wrote:
Hi Dmitry, As a previous suggester of metadata information built-in into PHP, and also one of developers of the most used metadata library written in PHP, I understand this feature implementation requires several design decisions and also a good understanding of specific situations users may require. While I am a strong supporter of a more robust solution, this is already a good start. A few things I'd like to ask for my own understanding and also suggestions too: 1- I understand you took a minimalistic approach towards a "dumb" implementation for attributes (when I mean "dumb", the idea here is towards a non-OO approach). Can you explain your motivations towards this approach? I see two distinct approaches of implementation for this feature. Both of them have some common demands, like lazy initialization of metadata. Here they are: - Simplistic approach, which lets consumers of the feature do all the work related to validation, assertion of valid keys, values, etc This does not invalidate the ability to leverage of some features that a more robust implementation demands. - Robust approach: language takes the burden of instantiating complex structures, validating, assertion of valid keys, values, if this complex structure is allowed to be instantiated in that given class, method, etc.
I didn't exactly understand what do you suggest. If you are talking about Attribute objects initialization during compilation - this is just not possible from implementation point of view. Now attributes may be stored in opcache SHM and relive request boundary. Objects can't relive requests.
I know that object instances are not cross-requests. Explicitly, I
mentioned that both approaches require lazy-initialization (which
means, whenever you call getAttributes() or getAttribute()).What I mentioning is that your approach is basically a new key/value
syntax that are used specifically for Attributes. We could easily turn
this into a more robust approach if instead of defining key/value
pairs, we instantiate objects or call functions. You already
demonstrated interest to support <<ORM\Entity>> reusing the imports
(which is our biggest headache in Doctrine Annotations), so why not
issue constructor or function calls there? That would simplify the
work needed for consumers and also add room for later improvements.
So basically in this example:use Doctrine\ORM;
<<ORM\Entity("user")>>
class User {}$reflClass = new \ReflectionClass("User");
var_dump($reflClass->getAttributes());We'd be changing from this:
array(1) {
["Doctrine\ORM\Entity"]=>
array(1) {
[0]=>
string(4) "user"
}
}Into this:
array(1) {
["Doctrine\ORM\Entity"]=>
object(Doctrine\ORM\Entity)#1 (1) {
["tableName"]=>
string(4) "user"
}
}
As I showed already, it's very easy to do this transformation at higher
layer.
$reflClass = new \ReflectionClass("User");
$attributes = $reflClass->getAttributes()
foreach ($attributes as $key => &$val) {
$val = new $key(...$val);
}
var_dump($attributes);
Construction objects directly in Reflection*::getAttributes() method,
doesn't make significant benefits and even makes limitation.
1- Your approach is basically defining an array. Could you explain your line of thinking on why you didn't consider a syntax like the one below? <["key" => "value"]> class Foo {}
I didn't try to invite new syntax. Just completely took it from HHVM.
My idea was based on your current proposal, which is basically a way
to define key/value pairs.
If you decide to go minimalistic, that is probably my best line of
thinking.2- I see that you added support over functions, classes, constants and properties. According to the RFC, getAttributes() was added over ReflectionFunction. Is there a reason why support was not added to methods (ReflectionMethod extends ReflectionFunctionAbstract, which was not mentioned on RFC)? Any reason to not support it in function/method parameters?
ReflectionMethod is a child of ReflectinFunction, so it's supported. Attributes are allowed for the same entities as doc-comments (they are not allowed for parameters)
I was asking if there was a purpose to not support Attributes over
ReflectionParameter. Example:class Foo {
public function bar(<<Qux>> Bar $bar) : bool {
// ...
}
}$reflClass = new \ReflectionClas("Foo");
$reflMethod = $reflClass->getMethod("bar");
$reflParameter = $reflMethod->getParameters()[0];var_dump($reflParameter->getAttributes());
I understood, we may add this ability later.
3- Did you put any thought on inheritance? What I mentioned in comment #1 is even smaller than what you implemented in RFC. Assuming you keep the RFC approach, did you consider support overrides, inherit, etc?
In my opinion, attributes don't have to be inherited. If you think differently - please explain your point.
Of source I can.
A simple case would be to increate visibility of the inherited
property. It was declared in a parent class as protected, but now you
want public, and you still want to keep all parent defined Attributes.
Very questionable. If you redefine property, it shouldn't inherit
attributes.
Another example is like we do in Doctrine. We support a callback
system which we named as lifetime callbacks. Pre-persist is one of
them, which is called every time a given Entity is about to be
persisted into DB. When you're dealing with inheritance, you can
potentially override the method content and you still want to trigger
the same operation as if it was untouched. Example:use Doctrine\ORM;
trait Timestampable {
protected $created;
protected $updated;<<ORM\PrePersist>>
public function prePersist() {
$this->created = $this->updated = new \DateTime("now");
}<<ORM\PreUpdate>>
public function preUpdate() {
$this->updated = new \DateTime("now");
}
}<<ORM\Entity>>
class User {
use Timestampable;public function prePersist() { // Add my custom logic }
}
The implication is that through a simplistic approach, inheriting (or
overriding) is not clear and I can't figure it out an easy way to
achieve that.
Now if we go towards calling a function or class constructor like I
mentioned before, then we could easily build structures like
__Inherit, __Override, etc.
It's definitely, not clear when attribute inheritance make sense and
when completely not. For example, if we mark some method to be JIT-ed,
it doesn't mean that we like to JIT methods of all children. So, I
prefer not to do inheritance at all. The higher layers may emulate
"inheritance" of some attributes their selves (like you do this with
doc-comments).
4- I understand that a more robust attribute solution would be required to achieve this, but one of the biggest advantages of AOP is the ability to perform custom logic before, after or around... However, I don't know if any kind of triggers came in your head or are planned as a future RFC. Let me highlight one example: Every time a class, property or method is called that is annotated as <<deprecated>>, I would like to issue an `E_USER_DEPRECATED` warning. A trigger-like solution would be required. Did this concept came to your mind?
This is not a subject of this RFC. Attributes provides a storage for metadata, but don't define how to use them. Especially, for your use-case: 1) it's possible to create preprocessor that embeds corresponding `trigger_error()` call 2) it's possible to write a PHP extension that plugs-into compiler chain and checks <<deprecated>> attribute for each compiles function, then sets ZEND_ACC_DEPRECATED flag 3) It's also possible to override DO_FCALL opcodes and perform checks there (this is inefficient)
With this simplistic approach, I agree there's 0 value into
considering this.
However, taking a more robust approach would potentially open this
possibility through a simpler extension.
You saw, Sara named even this proposed solution a bit over-designed.
it make no sense to implement all functionality at language level.
Actually, keeping simple base interface, opens doors for more use-cases.
Thanks. Dmitry.
Thanks. Dmitry.
Regards, On Thu, Apr 21, 2016 at 7:44 PM, Dmitry Stogov <dmitry@zend.com <mailto:dmitry@zend.com>> wrote: This is amazing. It would actually allow us to implement our automated assertions ourselves, as opposed to requiring it within the language. this was the idea - to give a good tool instead of implementing every possible use-case in the language. Could it also support references? <<sanitize(&$a)>> function foo($a) { } yes. "&$a" is a valid PHP expression. If you plan to use this, I would appreciate, if you to build the patched PHP and try it. The early we find problems the better feature we will get at the end. Thanks. Dmitry. On 21 Apr 2016 10:13 p.m., "Dmitry Stogov" <dmitry@zend.com <mailto:dmitry@zend.com> <mailto:dmitry@zend.com <mailto:dmitry@zend.com>>> 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. -- Guilherme Blanco Lead Architect at E-Block
--
Guilherme Blanco
Lead Architect at E-Block
>
>
>
>
>
>
>
>>
>>
>> On 04/22/2016 04:05 AM,
>> guilhermeblanco@gmail.com wrote:
>>
>> Hi Dmitry,
>>
>> As a previous suggester of metadata information built-in into PHP, and
>> also one of developers of the most used metadata library written in PHP, I
>> understand this feature implementation requires several design decisions
>> and also a good understanding of specific situations users may require.
>>
>> While I am a strong supporter of a more robust solution, this is already
>> a good start.
>> A few things I'd like to ask for my own understanding and also
>> suggestions too:
>>
>> 1- I understand you took a minimalistic approach towards a "dumb"
>> implementation for attributes (when I mean "dumb", the idea here is towards
>> a non-OO approach). Can you explain your motivations towards this approach?
>>
>> I see two distinct approaches of implementation for this feature. Both of
>> them have some common demands, like lazy initialization of metadata. Here
>> they are:
>>
>> - Simplistic approach, which lets consumers of the feature do all the
>> work related to validation, assertion of valid keys, values, etc
>> This does not invalidate the ability to leverage of some features that a
>> more robust implementation demands.
>>
>> - Robust approach: language takes the burden of instantiating complex
>> structures, validating, assertion of valid keys, values, if this complex
>> structure is allowed to be instantiated in that given class, method, etc.
>>
>>
>> I didn't exactly understand what do you suggest.
>> If you are talking about Attribute objects initialization during
>> compilation - this is just not possible from implementation point of view.
>> Now attributes may be stored in opcache SHM and relive request boundary.
>> Objects can't relive requests.
>>
>
>
> I know that object instances are not cross-requests. Explicitly, I
> mentioned that both approaches require lazy-initialization (which means,
> whenever you call getAttributes() or getAttribute()).
>
> What I mentioning is that your approach is basically a new key/value
> syntax that are used specifically for Attributes. We could easily turn this
> into a more robust approach if instead of defining key/value pairs, we
> instantiate objects or call functions. You already demonstrated interest to
> support <
> in Doctrine Annotations), so why not issue constructor or function calls
> there? That would simplify the work needed for consumers and also add room
> for later improvements.
>
> So basically in this example:
>
> use Doctrine\ORM;
>
> <
> class User {}
>
> $reflClass = new \ReflectionClass("User");
> var_dump($reflClass->getAttributes());
>
> We'd be changing from this:
>
> array(1) {
> ["Doctrine\ORM\Entity"]=>
> array(1) {
> [0]=>
> string(4) "user"
> }
> }
>
> Into this:
>
> array(1) {
> ["Doctrine\ORM\Entity"]=>
> object(Doctrine\ORM\Entity)#1 (1) {
> ["tableName"]=>
> string(4) "user"
> }
> }
>
>
> As I showed already, it's very easy to do this transformation at higher
> layer.
>
> $reflClass = new \ReflectionClass("User");
> $attributes = $reflClass->getAttributes()
> foreach ($attributes as $key => &$val) {
> $val = new $key(...$val);
> }
> var_dump($attributes);
>
> Construction objects directly in Reflection*::getAttributes() method,
> doesn't make significant benefits and even makes limitation.
>
Sorry, but I don't see how limitations are added. If you call a function,
static method or constructor, you actually add whole new level of
possibilities, and I fail to see which limitations are added. Could you
provide me one?
Calling the function/constructor/static method, not only helps to better
segregate userland code, but it also adds subsequents extensibility. I can
highlight examples:
- Support for Inheritance and overrides, through @Inherit, @Override, etc.
While you might not see how it could be used now, other developers might be
weirdly creative.
- Targeting of annotations, such as limiting its scope to be only class,
method or property. We use this extensively in Doctrine, where you cannot
define Doctrine\ODM\Entity over a property.
- Separating what can be considered as an annotation and what cannot.
Built-in @Annotation as a marker would differentiate that I can do call
Doctrine\ORM\Entity and not Doctrine\ORM\UnitOfWork.
- Make it easier to support an AOP extension, where it could detect
annotations being used and override DO_FCALL to call before, after or
around through the implementation of interfaces.
- If we ever decide to support named parameters, taking advantage of that
would become natural, like: <
>
>
>
>
>>
>> 1- Your approach is basically defining an array. Could you explain your
>> line of thinking on why you didn't consider a syntax like the one below?
>>
>> <["key" => "value"]>
>> class Foo {}
>>
>> I didn't try to invite new syntax. Just completely took it from HHVM.
>>
>
> My idea was based on your current proposal, which is basically a way to
> define key/value pairs.
> If you decide to go minimalistic, that is probably my best line of
> thinking.
>
>
>>
>>
>>
>> 2- I see that you added support over functions, classes, constants and
>> properties. According to the RFC, getAttributes() was added over
>> ReflectionFunction. Is there a reason why support was not added to methods
>> (ReflectionMethod extends ReflectionFunctionAbstract, which was not
>> mentioned on RFC)? Any reason to not support it in function/method
>> parameters?
>>
>> ReflectionMethod is a child of ReflectinFunction, so it's supported.
>>
> Attributes are allowed for the same entities as doc-comments (they are not
>> allowed for parameters)
>>
>
> I was asking if there was a purpose to not support Attributes over
> ReflectionParameter. Example:
>
> class Foo {
> public function bar(<
> // ...
> }
> }
>
> $reflClass = new \ReflectionClas("Foo");
> $reflMethod = $reflClass->getMethod("bar");
> $reflParameter = $reflMethod->getParameters()[0];
>
> var_dump($reflParameter->getAttributes());
>
>
> I understood, we may add this ability later.
>
I'd say we should add this from day one.
A quick use case that comes to my mind are parameters conversion that
happens in Symfony2 through their "extra" bundle (doc:
http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html
). In a controller action (it's a class method), you have the ability to
convert the Request object into something else that makes more sense for
you. Example:
class UserController extends Controller {
public function viewAction(<
$user = null) {
if ($user === null) {
throw new NotFoundException("User not found");
}
return ["me" => $this->getUser(), "user" => $user];
}
}
>
>
>
>>
>>
>>
>> 3- Did you put any thought on inheritance? What I mentioned in comment #1
>> is even smaller than what you implemented in RFC.
>> Assuming you keep the RFC approach, did you consider support overrides,
>> inherit, etc?
>>
>>
>> In my opinion, attributes don't have to be inherited.
>> If you think differently - please explain your point.
>>
>
> Of source I can.
> A simple case would be to increate visibility of the inherited property.
> It was declared in a parent class as protected, but now you want public,
> and you still want to keep all parent defined Attributes.
>
> Very questionable. If you redefine property, it shouldn't inherit
> attributes.
>
This leads to some serious copy/paste, highly error prone... =(
>
>
> Another example is like we do in Doctrine. We support a callback system
> which we named as lifetime callbacks. Pre-persist is one of them, which is
> called every time a given Entity is about to be persisted into DB. When
> you're dealing with inheritance, you can potentially override the method
> content and you still want to trigger the same operation as if it was
> untouched. Example:
>
> use Doctrine\ORM;
>
> trait Timestampable {
> protected $created;
> protected $updated;
>
> <
> public function prePersist() {
> $this->created = $this->updated = new \DateTime("now");
> }
>
> <
> public function preUpdate() {
> $this->updated = new \DateTime("now");
> }
> }
>
> <
> class User {
> use Timestampable;
>
> public function prePersist() {
> // Add my custom logic
> }
> }
>
> The implication is that through a simplistic approach, inheriting (or
> overriding) is not clear and I can't figure it out an easy way to achieve
> that.
> Now if we go towards calling a function or class constructor like I
> mentioned before, then we could easily build structures like __Inherit,
> __Override, etc.
>
> It's definitely, not clear when attribute inheritance make sense and when
> completely not. For example, if we mark some method to be JIT-ed, it
> doesn't mean that we like to JIT methods of all children. So, I prefer not
> to do inheritance at all. The higher layers may emulate "inheritance" of
> some attributes their selves (like you do this with doc-comments).
>
As I said earlier, if you do a call based approach, we could create
@Inherit or @Override, which would not only make us safe from support, but
also gives more power to developers.
>
>
>
>
>>
>>
>> 4- I understand that a more robust attribute solution would be required
>> to achieve this, but one of the biggest advantages of AOP is the ability to
>> perform custom logic before, after or around... However, I don't know if
>> any kind of triggers came in your head or are planned as a future RFC.
>> Let me highlight one example: Every time a class, property or method is
>> called that is annotated as <
>> `E_USER_DEPRECATED` warning. A trigger-like solution would be required. Did
>> this concept came to your mind?
>>
>> This is not a subject of this RFC.
>> Attributes provides a storage for metadata, but don't define how to use
>> them.
>> Especially, for your use-case:
>> 1) it's possible to create preprocessor that embeds corresponding
>> `trigger_error()` call
>> 2) it's possible to write a PHP extension that plugs-into compiler chain
>> and checks <
>> ZEND_ACC_DEPRECATED flag
>> 3) It's also possible to override DO_FCALL opcodes and perform checks
>> there (this is inefficient)
>>
>>
> With this simplistic approach, I agree there's 0 value into considering
> this.
> However, taking a more robust approach would potentially open this
> possibility through a simpler extension.
>
>
> You saw, Sara named even this proposed solution a bit over-designed.
> it make no sense to implement all functionality at language level.
> Actually, keeping simple base interface, opens doors for more use-cases.
>
> Thanks. Dmitry.
>
>
>
>
>
>> Thanks. Dmitry.
>>
>>
>>
>>
>>
>> Regards,
>>
>> On Thu, Apr 21, 2016 at 7:44 PM, Dmitry Stogov <
>> dmitry@zend.com> wrote:
>>
>>>
>>>
>>>
>>>
>>>>
>>>> This is amazing. It would actually allow us to implement our automated
>>>> assertions ourselves, as opposed to requiring it within the language.
>>>>
>>>> this was the idea - to give a good tool instead of implementing every
>>> possible use-case in the language.
>>>
>>> Could it also support references?
>>>>
>>>> <
>>>> function foo($a) {
>>>>
>>>> }
>>>>
>>>> yes. "&$a" is a valid PHP expression.
>>>
>>> If you plan to use this, I would appreciate, if you to build the patched
>>> PHP and try it.
>>> The early we find problems the better feature we will get at the end.
>>>
>>> Thanks. Dmitry.
>>>
>>>
>>> On 21 Apr 2016 10:13 p.m., "Dmitry Stogov"
>>>>
>>>> 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.
>>>>
>>>>
>>>
>>
>>
>> --
>> Guilherme Blanco
>> Lead Architect at E-Block
>>
>>
>>
>
>
> --
> Guilherme Blanco
> Lead Architect at E-Block
>
>
>
--
Guilherme Blanco
Lead Architect at E-Block
ReflectionClass, a new reflection_object gets created.
Isn't there a way to get this "cached" somehow in zend_class_entry?
On Mon, Apr 25, 2016 at 10:11 AM, guilhermeblanco@gmail.com <
guilhermeblanco@gmail.com> wrote:
>
>
>
>
>>
>>
>>
>>
>>
>>
>>
>>>
>>>
>>> On 04/22/2016 04:05 AM,
>>> guilhermeblanco@gmail.com wrote:
>>>
>>> Hi Dmitry,
>>>
>>> As a previous suggester of metadata information built-in into PHP, and
>>> also one of developers of the most used metadata library written in PHP, I
>>> understand this feature implementation requires several design decisions
>>> and also a good understanding of specific situations users may require.
>>>
>>> While I am a strong supporter of a more robust solution, this is already
>>> a good start.
>>> A few things I'd like to ask for my own understanding and also
>>> suggestions too:
>>>
>>> 1- I understand you took a minimalistic approach towards a "dumb"
>>> implementation for attributes (when I mean "dumb", the idea here is towards
>>> a non-OO approach). Can you explain your motivations towards this approach?
>>>
>>> I see two distinct approaches of implementation for this feature. Both
>>> of them have some common demands, like lazy initialization of metadata.
>>> Here they are:
>>>
>>> - Simplistic approach, which lets consumers of the feature do all the
>>> work related to validation, assertion of valid keys, values, etc
>>> This does not invalidate the ability to leverage of some features that a
>>> more robust implementation demands.
>>>
>>> - Robust approach: language takes the burden of instantiating complex
>>> structures, validating, assertion of valid keys, values, if this complex
>>> structure is allowed to be instantiated in that given class, method, etc.
>>>
>>>
>>> I didn't exactly understand what do you suggest.
>>> If you are talking about Attribute objects initialization during
>>> compilation - this is just not possible from implementation point of view.
>>> Now attributes may be stored in opcache SHM and relive request boundary.
>>> Objects can't relive requests.
>>>
>>
>>
>> I know that object instances are not cross-requests. Explicitly, I
>> mentioned that both approaches require lazy-initialization (which means,
>> whenever you call getAttributes() or getAttribute()).
>>
>> What I mentioning is that your approach is basically a new key/value
>> syntax that are used specifically for Attributes. We could easily turn this
>> into a more robust approach if instead of defining key/value pairs, we
>> instantiate objects or call functions. You already demonstrated interest to
>> support <
>> in Doctrine Annotations), so why not issue constructor or function calls
>> there? That would simplify the work needed for consumers and also add room
>> for later improvements.
>>
>> So basically in this example:
>>
>> use Doctrine\ORM;
>>
>> <
>> class User {}
>>
>> $reflClass = new \ReflectionClass("User");
>> var_dump($reflClass->getAttributes());
>>
>> We'd be changing from this:
>>
>> array(1) {
>> ["Doctrine\ORM\Entity"]=>
>> array(1) {
>> [0]=>
>> string(4) "user"
>> }
>> }
>>
>> Into this:
>>
>> array(1) {
>> ["Doctrine\ORM\Entity"]=>
>> object(Doctrine\ORM\Entity)#1 (1) {
>> ["tableName"]=>
>> string(4) "user"
>> }
>> }
>>
>>
>> As I showed already, it's very easy to do this transformation at higher
>> layer.
>>
>> $reflClass = new \ReflectionClass("User");
>> $attributes = $reflClass->getAttributes()
>> foreach ($attributes as $key => &$val) {
>> $val = new $key(...$val);
>> }
>> var_dump($attributes);
>>
>> Construction objects directly in Reflection*::getAttributes() method,
>> doesn't make significant benefits and even makes limitation.
>>
>
> Sorry, but I don't see how limitations are added. If you call a function,
> static method or constructor, you actually add whole new level of
> possibilities, and I fail to see which limitations are added. Could you
> provide me one?
>
> Calling the function/constructor/static method, not only helps to better
> segregate userland code, but it also adds subsequents extensibility. I can
> highlight examples:
>
> - Support for Inheritance and overrides, through @Inherit, @Override, etc.
> While you might not see how it could be used now, other developers might be
> weirdly creative.
> - Targeting of annotations, such as limiting its scope to be only class,
> method or property. We use this extensively in Doctrine, where you cannot
> define Doctrine\ODM\Entity over a property.
> - Separating what can be considered as an annotation and what cannot.
> Built-in @Annotation as a marker would differentiate that I can do call
> Doctrine\ORM\Entity and not Doctrine\ORM\UnitOfWork.
> - Make it easier to support an AOP extension, where it could detect
> annotations being used and override DO_FCALL to call before, after or
> around through the implementation of interfaces.
> - If we ever decide to support named parameters, taking advantage of that
> would become natural, like: <
>
>
>
>>
>>
>>
>>
>>>
>>> 1- Your approach is basically defining an array. Could you explain your
>>> line of thinking on why you didn't consider a syntax like the one below?
>>>
>>> <["key" => "value"]>
>>> class Foo {}
>>>
>>> I didn't try to invite new syntax. Just completely took it from HHVM.
>>>
>>
>> My idea was based on your current proposal, which is basically a way to
>> define key/value pairs.
>> If you decide to go minimalistic, that is probably my best line of
>> thinking.
>>
>>
>>>
>>>
>>>
>>> 2- I see that you added support over functions, classes, constants and
>>> properties. According to the RFC, getAttributes() was added over
>>> ReflectionFunction. Is there a reason why support was not added to methods
>>> (ReflectionMethod extends ReflectionFunctionAbstract, which was not
>>> mentioned on RFC)? Any reason to not support it in function/method
>>> parameters?
>>>
>>> ReflectionMethod is a child of ReflectinFunction, so it's supported.
>>>
>> Attributes are allowed for the same entities as doc-comments (they are
>>> not allowed for parameters)
>>>
>>
>> I was asking if there was a purpose to not support Attributes over
>> ReflectionParameter. Example:
>>
>> class Foo {
>> public function bar(<
>> // ...
>> }
>> }
>>
>> $reflClass = new \ReflectionClas("Foo");
>> $reflMethod = $reflClass->getMethod("bar");
>> $reflParameter = $reflMethod->getParameters()[0];
>>
>> var_dump($reflParameter->getAttributes());
>>
>>
>> I understood, we may add this ability later.
>>
>
> I'd say we should add this from day one.
> A quick use case that comes to my mind are parameters conversion that
> happens in Symfony2 through their "extra" bundle (doc:
> http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html
> ). In a controller action (it's a class method), you have the ability to
> convert the Request object into something else that makes more sense for
> you. Example:
>
> class UserController extends Controller {
> public function viewAction(<
> $user = null) {
> if ($user === null) {
> throw new NotFoundException("User not found");
> }
>
> return ["me" => $this->getUser(), "user" => $user];
> }
> }
>
>
>>
>>
>>
>>>
>>>
>>>
>>> 3- Did you put any thought on inheritance? What I mentioned in comment
>>> #1 is even smaller than what you implemented in RFC.
>>> Assuming you keep the RFC approach, did you consider support overrides,
>>> inherit, etc?
>>>
>>>
>>> In my opinion, attributes don't have to be inherited.
>>> If you think differently - please explain your point.
>>>
>>
>> Of source I can.
>> A simple case would be to increate visibility of the inherited property.
>> It was declared in a parent class as protected, but now you want public,
>> and you still want to keep all parent defined Attributes.
>>
>> Very questionable. If you redefine property, it shouldn't inherit
>> attributes.
>>
>
> This leads to some serious copy/paste, highly error prone... =(
>
>
>>
>>
>> Another example is like we do in Doctrine. We support a callback system
>> which we named as lifetime callbacks. Pre-persist is one of them, which is
>> called every time a given Entity is about to be persisted into DB. When
>> you're dealing with inheritance, you can potentially override the method
>> content and you still want to trigger the same operation as if it was
>> untouched. Example:
>>
>> use Doctrine\ORM;
>>
>> trait Timestampable {
>> protected $created;
>> protected $updated;
>>
>> <
>> public function prePersist() {
>> $this->created = $this->updated = new \DateTime("now");
>> }
>>
>> <
>> public function preUpdate() {
>> $this->updated = new \DateTime("now");
>> }
>> }
>>
>> <
>> class User {
>> use Timestampable;
>>
>> public function prePersist() {
>> // Add my custom logic
>> }
>> }
>>
>> The implication is that through a simplistic approach, inheriting (or
>> overriding) is not clear and I can't figure it out an easy way to achieve
>> that.
>> Now if we go towards calling a function or class constructor like I
>> mentioned before, then we could easily build structures like __Inherit,
>> __Override, etc.
>>
>> It's definitely, not clear when attribute inheritance make sense and when
>> completely not. For example, if we mark some method to be JIT-ed, it
>> doesn't mean that we like to JIT methods of all children. So, I prefer not
>> to do inheritance at all. The higher layers may emulate "inheritance" of
>> some attributes their selves (like you do this with doc-comments).
>>
>
> As I said earlier, if you do a call based approach, we could create
> @Inherit or @Override, which would not only make us safe from support, but
> also gives more power to developers.
>
>
>>
>>
>>
>>
>>>
>>>
>>> 4- I understand that a more robust attribute solution would be required
>>> to achieve this, but one of the biggest advantages of AOP is the ability to
>>> perform custom logic before, after or around... However, I don't know if
>>> any kind of triggers came in your head or are planned as a future RFC.
>>> Let me highlight one example: Every time a class, property or method is
>>> called that is annotated as <
>>> `E_USER_DEPRECATED` warning. A trigger-like solution would be required. Did
>>> this concept came to your mind?
>>>
>>> This is not a subject of this RFC.
>>> Attributes provides a storage for metadata, but don't define how to use
>>> them.
>>> Especially, for your use-case:
>>> 1) it's possible to create preprocessor that embeds corresponding
>>> `trigger_error()` call
>>> 2) it's possible to write a PHP extension that plugs-into compiler chain
>>> and checks <
>>> ZEND_ACC_DEPRECATED flag
>>> 3) It's also possible to override DO_FCALL opcodes and perform checks
>>> there (this is inefficient)
>>>
>>>
>> With this simplistic approach, I agree there's 0 value into considering
>> this.
>> However, taking a more robust approach would potentially open this
>> possibility through a simpler extension.
>>
>>
>> You saw, Sara named even this proposed solution a bit over-designed.
>> it make no sense to implement all functionality at language level.
>> Actually, keeping simple base interface, opens doors for more use-cases.
>>
>> Thanks. Dmitry.
>>
>>
>>
>>
>>
>>> Thanks. Dmitry.
>>>
>>>
>>>
>>>
>>>
>>> Regards,
>>>
>>> On Thu, Apr 21, 2016 at 7:44 PM, Dmitry Stogov <
>>> dmitry@zend.com> wrote:
>>>
>>>>
>>>>
>>>>
>>>>
>>>>>
>>>>> This is amazing. It would actually allow us to implement our
>>>>> automated assertions ourselves, as opposed to requiring it within the
>>>>> language.
>>>>>
>>>>> this was the idea - to give a good tool instead of implementing every
>>>> possible use-case in the language.
>>>>
>>>> Could it also support references?
>>>>>
>>>>> <
>>>>> function foo($a) {
>>>>>
>>>>> }
>>>>>
>>>>> yes. "&$a" is a valid PHP expression.
>>>>
>>>> If you plan to use this, I would appreciate, if you to build the
>>>> patched PHP and try it.
>>>> The early we find problems the better feature we will get at the end.
>>>>
>>>> Thanks. Dmitry.
>>>>
>>>>
>>>> On 21 Apr 2016 10:13 p.m., "Dmitry Stogov"
>>>>>
>>>>> 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.
>>>>>
>>>>>
>>>>
>>>
>>>
>>> --
>>> Guilherme Blanco
>>> Lead Architect at E-Block
>>>
>>>
>>>
>>
>>
>> --
>> Guilherme Blanco
>> Lead Architect at E-Block
>>
>>
>>
>
>
> --
> Guilherme Blanco
> Lead Architect at E-Block
>
--
Guilherme Blanco
Lead Architect at E-Block
guilhermeblanco@gmail.com wrote on 25/04/2016 15:22:
Another thing that looks odd to me i that every time you call new
ReflectionClass, a new reflection_object gets created.
Isn't there a way to get this "cached" somehow in zend_class_entry?
I recently came upon a package that exists solely to work around this:
https://packagist.org/packages/fsi/reflection
I am reminded of the fact that people often say "reflection is slow, use
it with care". Is this still the case? Does this limit the usability of
attributes as proposed?
Regards,
Rowan Collins
[IMSoP]
On Mon, Apr 25, 2016 at 7:11 PM, Rowan Collins rowan.collins@gmail.com
wrote:
guilhermeblanco@gmail.com wrote on 25/04/2016 15:22:
Another thing that looks odd to me i that every time you call new
ReflectionClass, a new reflection_object gets created.
Isn't there a way to get this "cached" somehow in zend_class_entry?I recently came upon a package that exists solely to work around this:
https://packagist.org/packages/fsi/reflectionI am reminded of the fact that people often say "reflection is slow, use
it with care". Is this still the case? Does this limit the usability of
attributes as proposed?
No its not slow, if you don't create Reflection* instances all the time. In
Doctrine we cache this per class and only do it once.
Guilherme came up with the why the object references are not reused on IRC,
because setAccessible could otherwise produce side effects to other
instances. So this actually makes sense.
Regards,
Rowan Collins
[IMSoP]
On Mon, Apr 25, 2016 at 3:42 AM, Dmitry Stogov <dmitry@zend.com
mailto:dmitry@zend.com> wrote:On 04/22/2016 06:39 PM, guilhermeblanco@gmail.com <mailto:guilhermeblanco@gmail.com> wrote:
On Fri, Apr 22, 2016 at 3:07 AM, Dmitry Stogov <dmitry@zend.com <mailto:dmitry@zend.com>> wrote: On 04/22/2016 04:05 AM, guilhermeblanco@gmail.com <mailto:guilhermeblanco@gmail.com> wrote:
Hi Dmitry, As a previous suggester of metadata information built-in into PHP, and also one of developers of the most used metadata library written in PHP, I understand this feature implementation requires several design decisions and also a good understanding of specific situations users may require. While I am a strong supporter of a more robust solution, this is already a good start. A few things I'd like to ask for my own understanding and also suggestions too: 1- I understand you took a minimalistic approach towards a "dumb" implementation for attributes (when I mean "dumb", the idea here is towards a non-OO approach). Can you explain your motivations towards this approach? I see two distinct approaches of implementation for this feature. Both of them have some common demands, like lazy initialization of metadata. Here they are: - Simplistic approach, which lets consumers of the feature do all the work related to validation, assertion of valid keys, values, etc This does not invalidate the ability to leverage of some features that a more robust implementation demands. - Robust approach: language takes the burden of instantiating complex structures, validating, assertion of valid keys, values, if this complex structure is allowed to be instantiated in that given class, method, etc.
I didn't exactly understand what do you suggest. If you are talking about Attribute objects initialization during compilation - this is just not possible from implementation point of view. Now attributes may be stored in opcache SHM and relive request boundary. Objects can't relive requests. I know that object instances are not cross-requests. Explicitly, I mentioned that both approaches require lazy-initialization (which means, whenever you call getAttributes() or getAttribute()). What I mentioning is that your approach is basically a new key/value syntax that are used specifically for Attributes. We could easily turn this into a more robust approach if instead of defining key/value pairs, we instantiate objects or call functions. You already demonstrated interest to support <<ORM\Entity>> reusing the imports (which is our biggest headache in Doctrine Annotations), so why not issue constructor or function calls there? That would simplify the work needed for consumers and also add room for later improvements. So basically in this example: use Doctrine\ORM; <<ORM\Entity("user")>> class User {} $reflClass = new \ReflectionClass("User"); var_dump($reflClass->getAttributes()); We'd be changing from this: array(1) { ["Doctrine\ORM\Entity"]=> array(1) { [0]=> string(4) "user" } } Into this: array(1) { ["Doctrine\ORM\Entity"]=> object(Doctrine\ORM\Entity)#1 (1) { ["tableName"]=> string(4) "user" } }
As I showed already, it's very easy to do this transformation at higher layer. $reflClass = new \ReflectionClass("User"); $attributes = $reflClass->getAttributes() foreach ($attributes as $key => &$val) { $val = new $key(...$val); } var_dump($attributes); Construction objects directly in Reflection*::getAttributes() method, doesn't make significant benefits and even makes limitation.
Sorry, but I don't see how limitations are added. If you call a
function, static method or constructor, you actually add whole new
level of possibilities, and I fail to see which limitations are added.
Could you provide me one?
For example, I like to check an attribute existence, and I don't need to
construct any objects.
Calling the function/constructor/static method, not only helps to
better segregate userland code, but it also adds subsequents
extensibility. I can highlight examples:
- Support for Inheritance and overrides, through @Inherit, @Override,
etc. While you might not see how it could be used now, other
developers might be weirdly creative.- Targeting of annotations, such as limiting its scope to be only
class, method or property. We use this extensively in Doctrine, where
you cannot define Doctrine\ODM\Entity over a property.- Separating what can be considered as an annotation and what cannot.
Built-in @Annotation as a marker would differentiate that I can do
call Doctrine\ORM\Entity and not Doctrine\ORM\UnitOfWork.- Make it easier to support an AOP extension, where it could detect
annotations being used and override DO_FCALL to call before, after or
around through the implementation of interfaces.- If we ever decide to support named parameters, taking advantage of
that would become natural, like: <<ORM\Entity(tableName => "user")>>
See a new example at https://wiki.php.net/rfc/attributes#use_cases
It's already works.
I don't see any reason to rewrite that few PHP lines in C.
1- Your approach is basically defining an array. Could you explain your line of thinking on why you didn't consider a syntax like the one below? <["key" => "value"]> class Foo {}
I didn't try to invite new syntax. Just completely took it from HHVM. My idea was based on your current proposal, which is basically a way to define key/value pairs. If you decide to go minimalistic, that is probably my best line of thinking.
2- I see that you added support over functions, classes, constants and properties. According to the RFC, getAttributes() was added over ReflectionFunction. Is there a reason why support was not added to methods (ReflectionMethod extends ReflectionFunctionAbstract, which was not mentioned on RFC)? Any reason to not support it in function/method parameters?
ReflectionMethod is a child of ReflectinFunction, so it's supported. Attributes are allowed for the same entities as doc-comments (they are not allowed for parameters) I was asking if there was a purpose to not support Attributes over ReflectionParameter. Example: class Foo { public function bar(<<Qux>> Bar $bar) : bool { // ... } } $reflClass = new \ReflectionClas("Foo"); $reflMethod = $reflClass->getMethod("bar"); $reflParameter = $reflMethod->getParameters()[0]; var_dump($reflParameter->getAttributes());
I understood, we may add this ability later.
I'd say we should add this from day one.
A quick use case that comes to my mind are parameters conversion that
happens in Symfony2 through their "extra" bundle (doc:
http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html
). In a controller action (it's a class method), you have the ability
to convert the Request object into something else that makes more
sense for you. Example:class UserController extends Controller {
public function viewAction(<<UserParameterConverter("userId")>>
User $user = null) {
if ($user === null) {
throw new NotFoundException("User not found");
}return ["me" => $this->getUser(), "user" => $user]; }
}
I'll take a look into this, but you see, I'm not very interested in
wasting time implementing particular low-level details while the whole
idea is not accepted yet.
3- Did you put any thought on inheritance? What I mentioned in comment #1 is even smaller than what you implemented in RFC. Assuming you keep the RFC approach, did you consider support overrides, inherit, etc?
In my opinion, attributes don't have to be inherited. If you think differently - please explain your point. Of source I can. A simple case would be to increate visibility of the inherited property. It was declared in a parent class as protected, but now you want public, and you still want to keep all parent defined Attributes.
Very questionable. If you redefine property, it shouldn't inherit attributes.
This leads to some serious copy/paste, highly error prone... =(
If we had a theoretical approach for attribute inheritance, I would
implement it.
But I wouldn't invite any theory, because anyone is going to depend on
use-case.
Another example is like we do in Doctrine. We support a callback system which we named as lifetime callbacks. Pre-persist is one of them, which is called every time a given Entity is about to be persisted into DB. When you're dealing with inheritance, you can potentially override the method content and you still want to trigger the same operation as if it was untouched. Example: use Doctrine\ORM; trait Timestampable { protected $created; protected $updated; <<ORM\PrePersist>> public function prePersist() { $this->created = $this->updated = new \DateTime("now"); } <<ORM\PreUpdate>> public function preUpdate() { $this->updated = new \DateTime("now"); } } <<ORM\Entity>> class User { use Timestampable; public function prePersist() { // Add my custom logic } } The implication is that through a simplistic approach, inheriting (or overriding) is not clear and I can't figure it out an easy way to achieve that. Now if we go towards calling a function or class constructor like I mentioned before, then we could easily build structures like __Inherit, __Override, etc.
It's definitely, not clear when attribute inheritance make sense and when completely not. For example, if we mark some method to be JIT-ed, it doesn't mean that we like to JIT methods of all children. So, I prefer not to do inheritance at all. The higher layers may emulate "inheritance" of some attributes their selves (like you do this with doc-comments).
As I said earlier, if you do a call based approach, we could create
@Inherit or @Override, which would not only make us safe from support,
but also gives more power to developers.
If we implement built-in @Inherit and/or @Override, it's not a big
problem to copy attributes from parent.
Thanks. Dmitry.
4- I understand that a more robust attribute solution would be required to achieve this, but one of the biggest advantages of AOP is the ability to perform custom logic before, after or around... However, I don't know if any kind of triggers came in your head or are planned as a future RFC. Let me highlight one example: Every time a class, property or method is called that is annotated as <<deprecated>>, I would like to issue an `E_USER_DEPRECATED` warning. A trigger-like solution would be required. Did this concept came to your mind?
This is not a subject of this RFC. Attributes provides a storage for metadata, but don't define how to use them. Especially, for your use-case: 1) it's possible to create preprocessor that embeds corresponding `trigger_error()` call 2) it's possible to write a PHP extension that plugs-into compiler chain and checks <<deprecated>> attribute for each compiles function, then sets ZEND_ACC_DEPRECATED flag 3) It's also possible to override DO_FCALL opcodes and perform checks there (this is inefficient) With this simplistic approach, I agree there's 0 value into considering this. However, taking a more robust approach would potentially open this possibility through a simpler extension.
You saw, Sara named even this proposed solution a bit over-designed. it make no sense to implement all functionality at language level. Actually, keeping simple base interface, opens doors for more use-cases. Thanks. Dmitry.
Thanks. Dmitry.
Regards, On Thu, Apr 21, 2016 at 7:44 PM, Dmitry Stogov <dmitry@zend.com <mailto:dmitry@zend.com>> wrote: This is amazing. It would actually allow us to implement our automated assertions ourselves, as opposed to requiring it within the language. this was the idea - to give a good tool instead of implementing every possible use-case in the language. Could it also support references? <<sanitize(&$a)>> function foo($a) { } yes. "&$a" is a valid PHP expression. If you plan to use this, I would appreciate, if you to build the patched PHP and try it. The early we find problems the better feature we will get at the end. Thanks. Dmitry. On 21 Apr 2016 10:13 p.m., "Dmitry Stogov" <dmitry@zend.com <mailto:dmitry@zend.com> <mailto:dmitry@zend.com <mailto:dmitry@zend.com>>> 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. -- Guilherme Blanco Lead Architect at E-Block
-- Guilherme Blanco Lead Architect at E-Block
--
Guilherme Blanco
Lead Architect at E-Block
This leads to some serious copy/paste, highly error prone... =(
If we had a theoretical approach for attribute inheritance, I would
implement it.
But I wouldn't invite any theory, because anyone is going to depend on
use-case.
Realistically, I see only 3 possible approaches to consider:
- An overridden class/property/method always inherits its parent's
annotations/attributes, and you can add to them. - An overridden class/property/method never inherits its parent's
annotations/attributes, but you can repeat them. - Give users a syntactic toggle.
As I said earlier, if you do a call based approach, we could create
@Inherit or @Override, which would not only make us safe from
support, but also gives more power to developers.If we implement built-in @Inherit and/or @Override, it's not a big
problem to copy attributes from parent.
If I understand you correctly, that would be option 3. I would support
that as well, as it's consistent with how methods work: By default, they
override the parent method but you can call parent::whatever() to toggle
the parent behavior back on. Thus, I would suggest that when overriding
a class/property/method that has annotations, it NOT inherit
annotations/attributes by default. However, by adding an annotation of
<<__inherit>>
(Or some other internal-reserved keyword, I don't have strong feelings
on what it is) then the engine will automatically give you all the
annotations off of the parent, and union them with whatever additional
ones you add.
That of course raises interesting questions around interfaces and
traits, and how annotations on those comingle. Should annotations on
interfaces auto-apply to their implementations or should they require an
explicit <<__inherit>>? I'm undecided.
--Larry Garfield
On Mon, Apr 25, 2016 at 6:49 PM, Larry Garfield larry@garfieldtech.com
wrote:
This leads to some serious copy/paste, highly error prone... =(
If we had a theoretical approach for attribute inheritance, I would
implement it.
But I wouldn't invite any theory, because anyone is going to depend on
use-case.Realistically, I see only 3 possible approaches to consider:
- An overridden class/property/method always inherits its parent's
annotations/attributes, and you can add to them.- An overridden class/property/method never inherits its parent's
annotations/attributes, but you can repeat them.- Give users a syntactic toggle.
Why do we talk about inheritance at all? ReflectionClass/Method/Property
already have a well defined way of accessing the inherited data. Why should
it work differently for ReflectionAttribute:
Demonstration of how to get access to overwritten doc comments in case of
overwritting a base class:
Attributes should just work exactly the same and we are done.
As I said earlier, if you do a call based approach, we could create
@Inherit or @Override, which would not only make us safe from support, but
also gives more power to developers.If we implement built-in @Inherit and/or @Override, it's not a big
problem to copy attributes from parent.If I understand you correctly, that would be option 3. I would support
that as well, as it's consistent with how methods work: By default, they
override the parent method but you can call parent::whatever() to toggle
the parent behavior back on. Thus, I would suggest that when overriding a
class/property/method that has annotations, it NOT inherit
annotations/attributes by default. However, by adding an annotation of<<__inherit>>
(Or some other internal-reserved keyword, I don't have strong feelings on
what it is) then the engine will automatically give you all the annotations
off of the parent, and union them with whatever additional ones you add.That of course raises interesting questions around interfaces and traits,
and how annotations on those comingle. Should annotations on interfaces
auto-apply to their implementations or should they require an explicit
<<__inherit>>? I'm undecided.--Larry Garfield
Hi!
a class/property/method that has annotations, it NOT inherit
annotations/attributes by default. However, by adding an annotation of<<__inherit>>
(Or some other internal-reserved keyword, I don't have strong feelings
on what it is) then the engine will automatically give you all the
annotations off of the parent, and union them with whatever additional
ones you add.
Then it makes no sense to ban repeating annotations - because that's
what we effectively are doing here. Also, this assumes all annotations
are either of inheritable kind or not, and these two categories can
never be combined.
--
Stas Malyshev
smalyshev@gmail.com
Check here to see what we did for php-annotations:
It's somewhat similar to how C# does it, and it has worked quite nicely.
On Mon, Apr 25, 2016 at 8:40 PM, Stanislav Malyshev smalyshev@gmail.com
wrote:
Hi!
a class/property/method that has annotations, it NOT inherit
annotations/attributes by default. However, by adding an annotation of<<__inherit>>
(Or some other internal-reserved keyword, I don't have strong feelings
on what it is) then the engine will automatically give you all the
annotations off of the parent, and union them with whatever additional
ones you add.Then it makes no sense to ban repeating annotations - because that's
what we effectively are doing here. Also, this assumes all annotations
are either of inheritable kind or not, and these two categories can
never be combined.--
Stas Malyshev
smalyshev@gmail.com
Check here to see what we did for php-annotations:
It's somewhat similar to how C# does it, and it has worked quite nicely.
After some fun caused by the way projects keep getting rewritten to
comply with the latest undemocratic changes to coding style, I have a
copy of php-annotations working without composer and what is imediatly
obvious is that current PHPDoc standard could do with an update.
php-annotations has some nice extensions such as range and length, but
these have been culled from the current builds because they are not part
of the standard. The problem is of cause that phpdoc.org are now
defining that standard and applying their view of how code should be
written, and the tags no longer align with much of the legacy code,
which is why we still have the phpDocumentor1 versions being used.
docBloc annotation IS well established, but can we at least document a
core PHP view of what should be available, and how to extend that to
support the alternat tags people are looking for.
--
Lester Caine - G8HFL
Contact - http://lsces.co.uk/wiki/?page=contact
L.S.Caine Electronic Services - http://lsces.co.uk
EnquirySolve - http://enquirysolve.com/
Model Engineers Digital Workshop - http://medw.co.uk
Rainbow Digital Media - http://rainbowdigitalmedia.co.uk
I would like to present an RFC proposing support for native annotation.
I'm trying to imagine where the benefit of non-constant expressions comes in.
<<foo($a < 1)>>
Assuming we roll in php-ast at the same time (which is a big addition,
IMO, and deserves its own separate RFC), what are users meant to do
with this? Even if there's a use-case here, one could accomplish the
same thing with:
<<foo('$a < 1')>>
And manually running that string into php-ast if that's what the caller wanted.
Also, maybe I missed it, but I didn't see an answer to the question of
ambiguity between parsing the above as a straight string, versus
parsing it as a ZEND_AST_ZVAL. I'm sure the answer is "If the AST
tree is just a ZVAL, then it's provided as the compile-time
expression, but what about something else like this:
<<foo(1+1)>>
Logically, this is reducible to a single compile-time value, but it's
a complex expression, so would it be the value int(2)? Or
ZEND_AST_BINARY_OP(int(1), int(1))?
I just think that over-engineers what should be a simple annotation feature.
All that said, I love the proposal overall, and I can't wait to
propose builtin annotations like <<__Memoize>>, <<__Mock>>, and
similar.
-Sara
I would like to present an RFC proposing support for native annotation.
I'm trying to imagine where the benefit of non-constant expressions comes in.
<<foo($a < 1)>>
Assuming we roll in php-ast at the same time (which is a big addition,
IMO, and deserves its own separate RFC), what are users meant to do
with this? Even if there's a use-case here, one could accomplish the
same thing with:<<foo('$a < 1')>>
And manually running that string into php-ast if that's what the caller wanted.
Good point. It's really not a big deal to run
ast\parse_code($r->getAttributes()["foo"])
This would simplify the implementation a bit.
Also, maybe I missed it, but I didn't see an answer to the question of
ambiguity between parsing the above as a straight string, versus
parsing it as a ZEND_AST_ZVAL. I'm sure the answer is "If the AST
tree is just a ZVAL, then it's provided as the compile-time
expression, but what about something else like this:<<foo(1+1)>>
Logically, this is reducible to a single compile-time value, but it's
a complex expression, so would it be the value int(2)? Or
ZEND_AST_BINARY_OP(int(1), int(1))?
Currently this going to be an AST - ZEND_AST_BINARY_OP(int(1), int(1))I just think that over-engineers what should be a simple annotation feature.
This makes sense. I think, I'll follow your suggestion.
The only missing ability is syntax check for <expression> attribute values.
All that said, I love the proposal overall, and I can't wait to
propose builtin annotations like <<__Memoize>>, <<__Mock>>, and
similar.
I'm looking forward as well. :)
Thanks. Dmitry.
-Sara
I would like to present an RFC proposing support for native annotation.
I'm trying to imagine where the benefit of non-constant expressions
comes in.<<foo($a < 1)>>
Assuming we roll in php-ast at the same time (which is a big addition,
IMO, and deserves its own separate RFC), what are users meant to do
with this? Even if there's a use-case here, one could accomplish the
same thing with:<<foo('$a < 1')>>
And manually running that string into php-ast if that's what the
caller wanted.Good point. It's really not a big deal to run
ast\parse_code($r->getAttributes()["foo"])
This would simplify the implementation a bit.
I can't speak for the implementation details, but I see a few benefits
of having real AST vs a string.. You get syntax highlighting in editors,
and most importantly compile time syntax errors if you messed up.
Cheers
--
Jordi Boggiano
@seldaek - http://seld.be
All that said, I love the proposal overall, and I can't wait to
propose builtin annotations like <<__Memoize>>, <<__Mock>>, and
similar.
I'd rather see these two functionalities added as modifiers at the
language level instead since they change the code behavior rather
dramatically. Not sure if knowledge of them is of interest in stages
where annotations might not be readily available; this was a driving
factor in Kotlin's decision what becomes a modifier or annotation.[1]
<?php
final class A {
private memoized function f() {}
}
test class B extends A { // OK, despite final.
public function f() {} // Has access to private methods.
}
test class C extends B {} // OK
class D extends B {} // Fatal Error!
?>
I know that this is true for @invariant
, @require
, and @ensure
as
well, they are fully-fledged assertions after all. Especially the
@invariant
could be easily added as a magic method.
[assert]
assert.invariants = 1
<?php
final class Object {
public function __invariant() {}
}
?>
Both @require
and @ensure
are a bit harder to implement at language
level. The following is the best I can come up with and is inspired by
the Eiffel syntax.[2]
[assert]
assert.preconditions = 1
assert.postconditions = 1
<?php
class PreconditionError extends AssertionError {}
class PostconditionError extends AssertionError {}
final class Account {
public function withdraw(int $sum): void {
$this->balance -= $this->balance - $sum;
}
require {
$sum >= 0;
$sum <= ($this->balance - self::MIN_BALANCE);
}
ensure {
$this->balance === (old::$balance - $sum);
}
}
$account = new Account;
$account->withdraw(-10);
/*
Uncaught PreconditionError: $sum >= 0
*/
$account->withdraw(10);
/*
Uncaught PreconditionError: $sum <= ($this->balance - self::MIN_BALANCE)
*/
$account->deposit(10);
$account->withdraw(5);
/*
Uncaught PostconditionError: $this->balance === (old::$balance - $sum)
*/
?>
I actually think now that it would be better to go for this than for
annotations.
[1] http://blog.jetbrains.com/kotlin/2015/08/modifiers-vs-annotations/
[2]
https://archive.eiffel.com/doc/online/eiffel50/intro/language/invitation-07.html
--
Richard "Fleshgrinder" Fussenegger
The invariant could also be added as an additional branch to the class
instead of a method, since it would not work like a method.
class A {} invariant {}
function f() {} require {} ensure {}
This would also align nicely with closures and anonymous classes, which
is kind a problematic with annotations.
$A = new class {} invariant {};
$f = function () {} require {} ensure {};
The only thing that remains that might be of interest to both is
@throws
but that was not discussed at all as of yet.
use Ns\SomeException;
@throws SomeException
function f() {
}
This is at least how one would expect it to work and it is something
that should be covered by annotations and not as part of the language.
The ABNF should account for that:
ANNOTATION = "@" NAME [ " " VALUE ]
NAME = STRING
VALUE = QUOTED-STRING / PHP-REFERENCE / EXPRESSION
QUOTED-STRING = ( "'" / DQUOTE ) STRING ( "'" / DQUOTE )
EXPRESSION = PHP-CODE ";"
Where PHP references are any of the already possible ones:
use F\Q\C\N;
@annotation \F\Q\C\N
@annotation N
@annotation \F\Q\C\N::CONSTANT
@annotation N::CONSTANT
@annotation \F\Q\C\N::function()
@annotation N::function()
@annotation \F\Q\C\N::$variable
@annotation N::$variable
I also though some more about function support for annotations and this
would actually be a nice thing for userland.
annotation deprecated(Reflection $element, string $message = '') {
@trigger_error($message, E_USER_DEPRECATED);
}
@deprecated('because')
function x() {}
@deprecated
function y() {}
This would allow users to implement simple and easy reactive annotations
in userland. Even if this could or should be an extension of the feature
in the future, it should be thought about know. Simply because the
brackets make sense if such a feature is to be implemented. ;)
--
Richard "Fleshgrinder" Fussenegger
The invariant could also be added as an additional branch to the class
instead of a method, since it would not work like a method.class A {} invariant {}
function f() {} require {} ensure {}
This would also align nicely with closures and anonymous classes, which
is kind a problematic with annotations.
You are way off topic with this imho.
$A = new class {} invariant {};
$f = function () {} require {} ensure {};
The only thing that remains that might be of interest to both is
@throws
but that was not discussed at all as of yet.use Ns\SomeException;
@throws SomeException
function f() {}
This is at least how one would expect it to work and it is something
that should be covered by annotations and not as part of the language.
The ABNF should account for that:ANNOTATION = "@" NAME [ " " VALUE ]
NAME = STRING
VALUE = QUOTED-STRING / PHP-REFERENCE / EXPRESSION
QUOTED-STRING = ( "'" / DQUOTE ) STRING ( "'" / DQUOTE )
EXPRESSION = PHP-CODE ";"
Where PHP references are any of the already possible ones:
use F\Q\C\N;
@annotation \F\Q\C\N
@annotation N
@annotation \F\Q\C\N::CONSTANT
@annotation N::CONSTANT
@annotation \F\Q\C\N::function()
@annotation N::function()
@annotation \F\Q\C\N::$variable
@annotation N::$variableI also though some more about function support for annotations and this
would actually be a nice thing for userland.annotation deprecated(Reflection $element, string $message = '') {
@trigger_error($message, E_USER_DEPRECATED);
}@deprecated('because')
function x() {}@deprecated
function y() {}
Attributes as proposed by Dimitry are not executing functions, they are
only metadata
that can be retrieved through reflection API. I think a python style
decorator approach
that you propose here, executing functions is not what the different
pro-annotations,
pro-attributes or pro-DesignByContract fractions want/need.
You are proposing something along the lines of AOP, which is an entirely
different beast
in my opinion.
This would allow users to implement simple and easy reactive annotations
in userland. Even if this could or should be an extension of the feature
in the future, it should be thought about know. Simply because the
brackets make sense if such a feature is to be implemented. ;)--
Richard "Fleshgrinder" Fussenegger
The invariant could also be added as an additional branch to the class
instead of a method, since it would not work like a method.class A {} invariant {}
function f() {} require {} ensure {}
This would also align nicely with closures and anonymous classes, which
is kind a problematic with annotations.You are way off topic with this imho.
No, not at all!
The RFC explicitly mentions design by contract (DbC) and that is why I
am responding to that. I do not think that annotations should or could
be used for DbC and want to raise this issue here. Of course all of the
above is a completely different story and requires its own RFC as well
as implementation. However, DbC should not be used to justify the
addition of annotations to PHP. (If libraries choose to use it for that,
different story.)
Attributes as proposed by Dimitry are not executing functions, they are
only metadata
that can be retrieved through reflection API. I think a python style
decorator approach
that you propose here, executing functions is not what the different
pro-annotations,
pro-attributes or pro-DesignByContract fractions want/need.You are proposing something along the lines of AOP, which is an entirely
different beast
in my opinion.
I know and that is why I am writing that the usage of brackets is not a
good idea because it suggests exactly that. We need to think about a
possible feature as outlined by myself (reactive annotations or /Python
style decorator approach/ as you call it) in order to not implement
annotations in a way that would kill exactly such a feature in a
possible future.
Hence, I am not off topic because I am thinking outside of the box in
the context of the whole ecosystem. Something that I see not happening
in this RFC nor its discussion.
--
Richard "Fleshgrinder" Fussenegger
On Sun, Apr 24, 2016 at 10:24 AM, Fleshgrinder php@fleshgrinder.com
wrote:The invariant could also be added as an additional branch to the class
instead of a method, since it would not work like a method.class A {} invariant {}
function f() {} require {} ensure {}
This would also align nicely with closures and anonymous classes, which
is kind a problematic with annotations.You are way off topic with this imho.
No, not at all!
The RFC explicitly mentions design by contract (DbC) and that is why I
am responding to that.
It mentions DbC as one userland use-case for attributes. This proposal is a
generic
feature that allows DbC, but much other stuff like configuration
(Annotation style).
As a generic buidling block like Dimitry proposes them attributes are
amazing and will
allow many more different use-cases in userland, proposing anything less
generic
will not get wide-spread support considering that these kind of changes
need 2/3 votes.
I do not think that annotations should or could
be used for DbC and want to raise this issue here. Of course all of the
above is a completely different story and requires its own RFC as well
as implementation. However, DbC should not be used to justify the
addition of annotations to PHP. (If libraries choose to use it for that,
different story.)Attributes as proposed by Dimitry are not executing functions, they are
only metadata
that can be retrieved through reflection API. I think a python style
decorator approach
that you propose here, executing functions is not what the different
pro-annotations,
pro-attributes or pro-DesignByContract fractions want/need.You are proposing something along the lines of AOP, which is an entirely
different beast
in my opinion.I know and that is why I am writing that the usage of brackets is not a
good idea because it suggests exactly that. We need to think about a
possible feature as outlined by myself (reactive annotations or /Python
style decorator approach/ as you call it) in order to not implement
annotations in a way that would kill exactly such a feature in a
possible future.
Hence, I am not off topic because I am thinking outside of the box in
the context of the whole ecosystem. Something that I see not happening
in this RFC nor its discussion.
Using attributes as a generic building block, you could implement a PECL
AOP extension doing the following:
- in every call check if that function/method has attributes.
- if it has an attribute "around(fn)", then call fn around the call
- If it has an attribute "before(fn)", then call fn before the call
- ...
This is similar to what Dimitry wants to do, adding DbC as a pecl extension
would be possible
with attributes, by evaluating the AST Attribute nodes before each function
call.
This is why we need attributes in this generic way, because it opens up
tons of possibilities
in a way that a large majority of php contributors thinks this is
worthwhile adding to the language.
AOP in general however, i doubt will ever be in PHP core similar to DbC,
but attributes allows to add
them easily as PECL extensions.
--
Richard "Fleshgrinder" Fussenegger
I am not arguing against the RFC nor the feature itself, on the
contrary, I like it. I just do not like certain aspects and design
decisions of it; that is all.
Configuration and AOP are the best usecases for annotations and those
should be stressed in the RFC. They are not mentioned at all!
Another usecase that I am missing completely is the usage of it for
documentation and static code analysis. I already mentioned the /throws/
annotation, this could help e.g. IDEs to warn you better about uncatched
exceptions form methods you call.
DbC is a possible usecase but better implemented at language level. The
RFC could mention the possibility of it. However, right now it is the
sole usecase beside the not very PHP applicable <<inline>>
and
<<jit>>
examples.
You see, this is more a problem of the RFC text and not of the feature. ;)
Another think I complained about is the proposed syntax because it makes
annotations look like function calls, which they simply are not and will
not be. The syntax is misleading and a possible built-in functionality
of reactive annotations (not saying we need them) at the language level
for userland is blocked. I know I just repeated myself.
The extension you mentioned works just fine without the brackets.
@invariant CONDITION;
class A {
@ensure CONDITION;
@require CONDITION;
function f(){}
}
--
Richard "Fleshgrinder" Fussenegger
I am not arguing against the RFC nor the feature itself, on the
contrary, I like it. I just do not like certain aspects and design
decisions of it; that is all.Configuration and AOP are the best usecases for annotations and those
should be stressed in the RFC. They are not mentioned at all!Another usecase that I am missing completely is the usage of it for
documentation and static code analysis. I already mentioned the /throws/
annotation, this could help e.g. IDEs to warn you better about uncatched
exceptions form methods you call.DbC is a possible usecase but better implemented at language level. The
RFC could mention the possibility of it. However, right now it is the
sole usecase beside the not very PHP applicable<<inline>>
and
<<jit>>
examples.You see, this is more a problem of the RFC text and not of the feature. ;)
Another think I complained about is the proposed syntax because it makes
annotations look like function calls, which they simply are not and will
not be. The syntax is misleading and a possible built-in functionality
of reactive annotations (not saying we need them) at the language level
for userland is blocked. I know I just repeated myself.The extension you mentioned works just fine without the brackets.
@invariant CONDITION;
class A {@ensure CONDITION; @require CONDITION; function f(){}
}
The proposed by you "@..." syntax just won't fit into PHP grammar,
because @ used as silence operator.
Attribute, syntax is taken from HHVM. I don't see a big reason to
introduce more fragmentation into PHP world.
Personally I don't see "foo(a,b,c)" as a function, I see this as a
predicate.
It's possible to extend RFC with additional use-cases, but the longer
the RFC the less people read it.
Thanks. Dmitry.
hi Dmitry,
Awesome work! Thanks.
I do like you keep what was discussed last time. Make the basics
available and leave the rest to the applications (doctrine or other).
I feel too that how the apps will interact with may need some more
discussions but other commented on it so I won't interfer here :).
The proposed by you "@..." syntax just won't fit into PHP grammar, because @
used as silence operator.Attribute, syntax is taken from HHVM. I don't see a big reason to introduce
more fragmentation into PHP world.
Also see https://docs.hhvm.com/hack/attributes/syntax and I fully
agree with Dmitry here. It makes no sense now to go with our own
syntax.
If any of the hhvm developers are around, we may get some feedbacks
about their current APIs (using getAttributes) and if they would like
to change one thing or another. That could (or must) part of the PHP
specifications.
Cheers,
Pierre
@pierrejoye | http://www.libgd.org
hi Dmitry,
Awesome work! Thanks.
I do like you keep what was discussed last time. Make the basics
available and leave the rest to the applications (doctrine or other).I feel too that how the apps will interact with may need some more
discussions but other commented on it so I won't interfer here :).
I've collected the most interesting feedback at
https://wiki.php.net/rfc/attributes#open_issues
And I'm going to correct RFC and implementation rethinking these questions.
Thanks. Dmitry.
The proposed by you "@..." syntax just won't fit into PHP grammar, because @
used as silence operator.Attribute, syntax is taken from HHVM. I don't see a big reason to introduce
more fragmentation into PHP world.
Also see https://docs.hhvm.com/hack/attributes/syntax and I fully
agree with Dmitry here. It makes no sense now to go with our own
syntax.If any of the hhvm developers are around, we may get some feedbacks
about their current APIs (using getAttributes) and if they would like
to change one thing or another. That could (or must) part of the PHP
specifications.Cheers,
Morning internals,
This morning I attempted to prototype a dbc extension.
In my opinion, the patch, or internals, are not fit for the intended
purpose.
At the moment, the *only* way to perform meta programming is going to
be in userland. This is going to make it prohibitively slow, and rather
pointless.
None of the compiler API is exported: This means that AST is almost
useless to internals unless it's a constant expression.
There is a problem with zend extensions and fcall handlers, which we
are not sure how to fix.
Working with AST is easy, working with opcodes directly is not.
Before we can have this, we must work on the AST API and allow
extensions to transform AST with much better hooks than we have at the
moment.
I was excited to start working with this .. at the moment, I'm -1.
Cheers
Joe
PS. If anyone is interested http://github.com/krakjoe/dbc was my first
attempt at interacting with the patch.
hi Dmitry,
Awesome work! Thanks.
I do like you keep what was discussed last time. Make the basics
available and leave the rest to the applications (doctrine or other).I feel too that how the apps will interact with may need some more
discussions but other commented on it so I won't interfer here :).I've collected the most interesting feedback at
https://wiki.php.net/rfc/attributes#open_issues
And I'm going to correct RFC and implementation rethinking these questions.Thanks. Dmitry.
The proposed by you "@..." syntax just won't fit into PHP grammar,
because @
used as silence operator.Attribute, syntax is taken from HHVM. I don't see a big reason to
introduce
more fragmentation into PHP world.Also see https://docs.hhvm.com/hack/attributes/syntax and I fully
agree with Dmitry here. It makes no sense now to go with our own
syntax.If any of the hhvm developers are around, we may get some feedbacks
about their current APIs (using getAttributes) and if they would like
to change one thing or another. That could (or must) part of the PHP
specifications.Cheers,
Forwarded, sorry for top post :(
---------- Forwarded message ----------
From: Joe Watkins pthreads@pthreads.org
Date: Mon, Apr 25, 2016 at 12:28 PM
Subject: Re: [PHP-DEV] [RFC] PHP Attributes
To: Dmitry Stogov dmitry@zend.com
Cc: Pierre Joye pierre.php@gmail.com, PHP internals <
internals@lists.php.net>, Benjamin Eberlei kontakt@beberlei.de, Sara
Golemon pollita@php.net
Morning internals,
This morning I attempted to prototype a dbc extension.
In my opinion, the patch, or internals, are not fit for the intended
purpose.
At the moment, the *only* way to perform meta programming is going to
be in userland. This is going to make it prohibitively slow, and rather
pointless.
None of the compiler API is exported: This means that AST is almost
useless to internals unless it's a constant expression.
There is a problem with zend extensions and fcall handlers, which we
are not sure how to fix.
Working with AST is easy, working with opcodes directly is not.
Before we can have this, we must work on the AST API and allow
extensions to transform AST with much better hooks than we have at the
moment.
I was excited to start working with this .. at the moment, I'm -1.
Cheers
Joe
PS. If anyone is interested http://github.com/krakjoe/dbc was my first
attempt at interacting with the patch.
hi Dmitry,
Awesome work! Thanks.
I do like you keep what was discussed last time. Make the basics
available and leave the rest to the applications (doctrine or other).I feel too that how the apps will interact with may need some more
discussions but other commented on it so I won't interfer here :).I've collected the most interesting feedback at
https://wiki.php.net/rfc/attributes#open_issues
And I'm going to correct RFC and implementation rethinking these questions.Thanks. Dmitry.
The proposed by you "@..." syntax just won't fit into PHP grammar,
because @
used as silence operator.Attribute, syntax is taken from HHVM. I don't see a big reason to
introduce
more fragmentation into PHP world.Also see https://docs.hhvm.com/hack/attributes/syntax and I fully
agree with Dmitry here. It makes no sense now to go with our own
syntax.If any of the hhvm developers are around, we may get some feedbacks
about their current APIs (using getAttributes) and if they would like
to change one thing or another. That could (or must) part of the PHP
specifications.Cheers,
Is there a reason why you think that Design by Contract (DbC) should be
implemented via annotations/attributes?
I personally think that such a system should be implemented directly in
the language, like Eiffel has it. I even think that it would be easy to
add it without any BC. It might be a bit more complicated to implement
thought.
[assert]
assert.active = 1
assert.invariant = 1
assert.require = 1 ; preconditions
assert.ensure = 1 ; postconditions
class PreconditionError extends AssertionError {}
class PostconditionError extends AssertionError {}
function hello(string $who): string {
return "Hello {$who}\n";
}
require {
# argument must have content
$who !== '';
# argument cannot contain unprintable characters
ctype_print($who);
}
hello('');
// PHP Warning: require(): argument must have content: "$who !== ''"
// failed in ...
hello("\0");
// PHP Warning: require(): argument cannot contain unprintable
// characters: "ctype_print($who)" failed in ...
class A {
private DateTimeImmutable $created;
private DateTimeImmutable $changed;
function f() {}
require {}
// Special scope "old" available...
ensure {
# error message
$this->x = old::$x - 42;
}
}
ensure {
# created cannot be less than changed time
$this->created <= $this->changed;
}
--
Richard "Fleshgrinder" Fussenegger
Hi!
I personally think that such a system should be implemented directly in
the language, like Eiffel has it. I even think that it would be easy to
I think we should not try to be Haskell, Scala and Eiffel at the same
time. DbC is not something most of the users of the language require and
would ever use, unlike Eiifel where it is major part of what the
language is. Giving a possibility of implementing it using attributes is
fine. But bringing yet another conceptual framework into PHP looks like
overkill to me.
--
Stas Malyshev
smalyshev@gmail.com
I think we should not try to be Haskell, Scala and Eiffel at the same
time. DbC is not something most of the users of the language require and
would ever use, unlike Eiifel where it is major part of what the
language is. Giving a possibility of implementing it using attributes is
fine. But bringing yet another conceptual framework into PHP looks like
overkill to me.
Yes, we should not be copy cats. However, we already have assert()
and
people are just discovering it, despite being there forever. I am not
proposing the previously mentioned syntax as a real RFC yet, simply
because I do not think that it is the right time to do so. However, I do
believe that DbC does not belong into meta-attributes.
My question remains: why DbC in meta? What could be any advantages?
--
Richard "Fleshgrinder" Fussenegger
Hi Fleshgrinder
Is there a reason why you think that Design by Contract (DbC) should be
implemented via annotations/attributes?
It's not complement of DbC, although it could be used.
Basic DbC idea is "Do validations always and fully during development
but disable almost all validations for production".
There are separated RFC for DbC
https://wiki.php.net/rfc/introduce_design_by_contract
https://wiki.php.net/rfc/dbc
https://wiki.php.net/rfc/dbc2
I like you version of syntax, but above syntax is the result of DbC
discussion so far.
I would like to reactivate DbC discussion soon...
Regards,
--
Yasuo Ohgaki
yohgaki@ohgaki.net
Morning internals,
This morning I attempted to prototype a dbc extension. In my opinion, the patch, or internals, are not fit for the
intended purpose.
At the moment, the *only* way to perform meta programming is going
to be in userland. This is going to make it prohibitively slow, and
rather pointless.
why? It's quite easy to use attributes in C extension.
if (op_array->attributes) {
zval *val = zend_hash_find_str(op_array->attributes, "requires",
sizeof("requires")-1_;
if (val && Z_TYPE_P(val) == IS_ARRAY) {
HashTable *ht = Z_ARRVAL_P(val);
ZEND_HASH_FORECH_VAL(ht, val) {
...
ZEND_HASH_FOREACH_END();
}
}
None of the compiler API is exported: This means that AST is
almost useless to internals unless it's a constant expression.
Do you mean C or PHP API?
What exactly do you like to be exported? zend_compile_expr()? It's not a
problem to export it in 7.1.
There is a problem with zend extensions and fcall handlers, which
we are not sure how to fix.
This is completely unrelated historical problem :)
Working with AST is easy, working with opcodes directly is not. Before we can have this, we must work on the AST API and allow
extensions to transform AST with much better hooks than we have at the
moment.
This is related to user extendable parser, that is definitely not a
subject of this RFC.
I was excited to start working with this .. at the moment, I'm -1.
I got you.
Attributes are not especially for DbC and user extendable parser, and
they are not a magic wand.
They may be an underlying layer for many things (including DbC).
But to reach what you want, you'll have to start from something anyway.
Thanks. Dmitry.
Cheers
JoePS. If anyone is interested http://github.com/krakjoe/dbc was my first
attempt at interacting with the patch.On Mon, Apr 25, 2016 at 11:08 AM, Dmitry Stogov <dmitry@zend.com
mailto:dmitry@zend.com> wrote:hi Dmitry, Awesome work! Thanks. I do like you keep what was discussed last time. Make the basics available and leave the rest to the applications (doctrine or other). I feel too that how the apps will interact with may need some more discussions but other commented on it so I won't interfer here :). I've collected the most interesting feedback at https://wiki.php.net/rfc/attributes#open_issues And I'm going to correct RFC and implementation rethinking these questions. Thanks. Dmitry. On Mon, Apr 25, 2016 at 3:17 PM, Dmitry Stogov <dmitry@zend.com <mailto:dmitry@zend.com>> wrote: The proposed by you "@..." syntax just won't fit into PHP grammar, because @ used as silence operator. Attribute, syntax is taken from HHVM. I don't see a big reason to introduce more fragmentation into PHP world. Also see https://docs.hhvm.com/hack/attributes/syntax and I fully agree with Dmitry here. It makes no sense now to go with our own syntax. If any of the hhvm developers are around, we may get some feedbacks about their current APIs (using getAttributes) and if they would like to change one thing or another. That could (or must) part of the PHP specifications. Cheers,
Hi!
The proposed by you "@..." syntax just won't fit into PHP grammar,
because @ used as silence operator.
Not sure why it is a problem more than << and >> being shift operators.
Since you said it can't be applied to anonymous functions/classes
anyway, parser with the help of AST should be able to figure out which
one is meant - I don't see a case where it's ambiguous.
Attribute, syntax is taken from HHVM. I don't see a big reason to
introduce more fragmentation into PHP world.
I don't think this is a good argument. It effectively means we now give
our language design to Facebook Hack team - whatever they do in Hack, we
then must follow, since otherwise it would be "more fragmentation". I
don't think it is a good position on our side.
--
Stas Malyshev
smalyshev@gmail.com
The invariant could also be added as an additional branch to the class
instead of a method, since it would not work like a method.class A {} invariant {}
function f() {} require {} ensure {}
This would also align nicely with closures and anonymous classes, which
is kind a problematic with annotations.$A = new class {} invariant {};
$f = function () {} require {} ensure {};
The only thing that remains that might be of interest to both is
@throws
but that was not discussed at all as of yet.use Ns\SomeException;
@throws SomeException
function f() {}
This is at least how one would expect it to work and it is something
that should be covered by annotations and not as part of the language.
The ABNF should account for that:ANNOTATION = "@" NAME [ " " VALUE ]
NAME = STRING
VALUE = QUOTED-STRING / PHP-REFERENCE / EXPRESSION
QUOTED-STRING = ( "'" / DQUOTE ) STRING ( "'" / DQUOTE )
EXPRESSION = PHP-CODE ";"Where PHP references are any of the already possible ones:
use F\Q\C\N;
@annotation \F\Q\C\N
@annotation N
@annotation \F\Q\C\N::CONSTANT
@annotation N::CONSTANT
@annotation \F\Q\C\N::function()
@annotation N::function()
@annotation \F\Q\C\N::$variable
@annotation N::$variableI also though some more about function support for annotations and this
would actually be a nice thing for userland.annotation deprecated(Reflection $element, string $message = '') {
@trigger_error($message, E_USER_DEPRECATED);
}@deprecated('because')
function x() {}@deprecated
function y() {}This would allow users to implement simple and easy reactive annotations
in userland. Even if this could or should be an extension of the feature
in the future, it should be thought about know. Simply because the
brackets make sense if such a feature is to be implemented. ;)
Looks interesting, but try to think where the "annotation deprecated"
should be declared,to be visible in every compiled script, when the
corresponding code should be called (in what context), what if we need
to do something at compile-time? Single answers to these question are
going to be great for "deprecated" use case, however they will limit
usability for other cases.
Thanks. Dmitry.
The invariant could also be added as an additional branch to the class
instead of a method, since it would not work like a method.class A {} invariant {}
function f() {} require {} ensure {}
This would also align nicely with closures and anonymous classes, which
is kind a problematic with annotations.$A = new class {} invariant {};
$f = function () {} require {} ensure {};
The only thing that remains that might be of interest to both is
@throws
but that was not discussed at all as of yet.use Ns\SomeException;
@throws SomeException
function f() {}
This is at least how one would expect it to work and it is something
that should be covered by annotations and not as part of the language.
The ABNF should account for that:ANNOTATION = "@" NAME [ " " VALUE ]
NAME = STRING
VALUE = QUOTED-STRING / PHP-REFERENCE / EXPRESSION
QUOTED-STRING = ( "'" / DQUOTE ) STRING ( "'" / DQUOTE )
EXPRESSION = PHP-CODE ";"Where PHP references are any of the already possible ones:
use F\Q\C\N;
@annotation \F\Q\C\N
@annotation N
@annotation \F\Q\C\N::CONSTANT
@annotation N::CONSTANT
@annotation \F\Q\C\N::function()
@annotation N::function()
@annotation \F\Q\C\N::$variable
@annotation N::$variableI also though some more about function support for annotations and this
would actually be a nice thing for userland.annotation deprecated(Reflection $element, string $message = '') {
@trigger_error($message, E_USER_DEPRECATED);
}@deprecated('because')
function x() {}@deprecated
function y() {}This would allow users to implement simple and easy reactive annotations
in userland. Even if this could or should be an extension of the feature
in the future, it should be thought about know. Simply because the
brackets make sense if such a feature is to be implemented. ;)Looks interesting, but try to think where the "annotation deprecated"
should be declared,to be visible in every compiled script, when the
corresponding code should be called (in what context), what if we need
to do something at compile-time? Single answers to these question are
going to be great for "deprecated" use case, however they will limit
usability for other cases.Thanks. Dmitry.
Reactive annotations would have their limitations, e.g. calls to the
reactive annotation function only happen during runtime and any attempts
to perform something at compile time directly results in an engine
error. It limits their use cases but allows interesting ones at the same
time.
Another approach could be to allow registration of reactive annotation
functions at runtime, this would make it even more useful. Of course
that would mean that the function is only called for each encountered
annotation at runtime after it was registered. However, such a
limitation is pretty much the same as we have it for any other function
right now too.
class User {
public function hasRole($right) {
if (false) {
throw new InsufficientPrivileges;
}
}
}
$user = new User();
register_annotation('Framework\Role', [ $user, 'hasRole' ]);
class Controller {
@Framework\Role('admin') public function editAction(){}
}
// ENGINE (pseudo code)
array registered_annotations = [];
void register_reactive_annotation(annotation, callback)
{
registered_annotations[annotation] = callback;
}
void reactive_annotation_call(annotation, ...arguments)
{
if (annotation exists in registered_annotations) {
call registered_annotationsannotation;
}
else {
log_info("Unknown reactive annotation %s", annotation);
}
}
However, this is a story for another RFC. It is only important because
usage of the brackets in the current RFC would make such a feature more
complicated to implement.
--
Richard "Fleshgrinder" Fussenegger
I would like to present an RFC proposing support for native annotation.
I thought that the debate had been completed on annotation, and since
most of the work can be done in a stand alone extension, the various
parties were going to take that route and develop working options which
could then be compared to decide if any provide a suitable replacement
for the current docbloc 'process' that most of the IDE's currently
recognise.
There is room for proper documentation of the current standard as some
elements are not followed reliably, but on the whole the system works,
and any of the new extensions need to be addressed via IDE projects
before they can replace that.
--
Lester Caine - G8HFL
Contact - http://lsces.co.uk/wiki/?page=contact
L.S.Caine Electronic Services - http://lsces.co.uk
EnquirySolve - http://enquirysolve.com/
Model Engineers Digital Workshop - http://medw.co.uk
Rainbow Digital Media - http://rainbowdigitalmedia.co.uk
Hi Dmitry!
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.
Just a couple of comments on this:
-
I'd definitely reuse the php-ast extension for parsing the code into an
AST. It performs a number of transformations on PHP's underlying AST
that make it much nicer to use (namely better consistency). It is also
less fragile by having the abstraction between PHP's internal AST and
the AST that is exposed to userland (enabling for internal AST changes
without impacting the AST exposed to userland). -
You mentioned about moving some of the php-ast extension into core.
I wonder if it would be better to just move the whole extension into the
core first, and then enable this functionality if the php-ast extension is
enabled.
Also, slightly tangential, but the RFC says attributes are supported on
class constants, yet doc comments (IIRC) are not. I wonder if support
for doc comments should be added for class constants?
Thanks,
Tom
Hi Dmitry!
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.
Just a couple of comments on this:
- I'd definitely reuse the php-ast extension for parsing the code into an
AST. It performs a number of transformations on PHP's underlying AST
that make it much nicer to use (namely better consistency). It is also
less fragile by having the abstraction between PHP's internal AST and
the AST that is exposed to userland (enabling for internal AST changes
without impacting the AST exposed to userland).
I'm not sure. Both approaches make sense.
- You mentioned about moving some of the php-ast extension into core.
I wonder if it would be better to just move the whole extension into the
core first, and then enable this functionality if the php-ast extension is
enabled.
Even if we move php-ast into core (I think we will do it), it's going to
be optional.
However attributes should always work.
Also, slightly tangential, but the RFC says attributes are supported on
class constants, yet doc comments (IIRC) are not. I wonder if support
for doc comments should be added for class constants?
it is already implemented.
Thanks. Dmitry.
Thanks,
Tom
+1 for the basic idea, however, I have various remarks.
The RFC text is hard to read and contains many grammatical mistakes. How
could one help you here?
I think that the Hack name attributes is unintelligible and annotations
would be much clearer to any audience. Simply because the name is very
well known.
I do not see the need for multi-annotation nor multi-value support. It
just creates multiple ways to achieve the exact same thing for no good
reason.
I do not like the <<>> syntax. It requires many key strokes, is hard to
read, and looks ugly. Why not simply @ and be done with it. I am not so
sure about the bracket requirement, is it somehow required for the
parsing? Otherwise I would leave it off. I guess it might be hard to
find the end of an annotation but have you considered to use the
semicolon for that? Would align nicely with existing PHP syntax. The
following would be the ABNF for my proposal:
ANNOTATION = "@" NAME [ " " VALUE ]
NAME = STRING
VALUE = QUOTED-STRING / PHP-CONSTANT / EXPRESSION
QUOTED-STRING = ( "'" / DQUOTE ) STRING ( "'" / DQUOTE )
EXPRESSION = PHP-CODE ";"
A semicolon would only be required if it is not a single quoted string
(see following example) or constant. A question that I see unanswered is
how embedding of variables in quoted strings should be dealt with. I see
no need for this but people might assume it is supported because PHP
supports it everywhere else.
<?php
$name = "Richard Fussenegger";
$email = "php@fleshgrinder.com";
@author "{$name} <{$email}>"
class A {}
<<author("{$name} <{$email}>")>>
class B {}
?>
Requiring PHP code to be terminated with a semicolon should also ensure
that people do not start to write fully-fledged programs in annotations.
Since that is not what they are intended for. An alternative approach I
see here would be to go for the brackets but then again only for PHP code:
EXPRESSION = "(" PHP-CODE ")"
Then again, it looks similar to a function call and this is imho not
good. Unless of course new annotations can be defined as special
functions directly in userland, e.g. with an annotation function
and/or annotation class
. However, this would require more thought.
Another question that is unanswered for me is: how to go about adding
annotations to a complete file as is currently possible with PhpDoc and
its file-level doc block:
<?php
@author 'Richard Fussenegger php@fleshgrinder.com'
@copyright '2016 Richard Fussenegger'
@license 'MIT'
declare(strict_types=1);
namespace Fleshgrinder\PhpInternals;
@description 'True annotation support could be a very good thing.'
@invariant $this->balance >= self::MIN_BALANCE;
class Account {
private const int MIN_BALANCE = 0;
private int $balance;
private Person $owner;
@require $sum >= 0;
@ensure $this->balance === (old::$balance + $sum);
public function deposit(int $sum): void {
$this->balance += $sum;
}
@require $sum >= 0;
@require $sum <= $this->balance - self::MIN_BALANCE;
@ensure $this->balance === (old::$balance - $sum);
public function withdraw(int $sum): void {
$this->balance -= $sum;
}
@deprecated 'for various reasons'
public function setOwner(Person $wner): void {
$this->owner = $owner;
}
}
@inheritDoc
class OverdraftAccount extends Account {
private const int MIN_BALANCE = -1000;
}
?>
We also need to make sure to add something regarding coding standards
for annotation names. I would propose to go for camelCase (same as for
method names) since this is what PhpDoc used to use for many years now.
We also need to define how people can avoid to collide with internal
annotations. The typical double-underscore prefix approach that we have
for magic methods creates a lot of visual clutter and looks weird if
spread among all kinds of places. A namespace approach as we have it
already for userland code could help here.
<?php
use Doctrine\ORM;
@ORM::entity
@ORM::table [
'name' => 'user',
'unique_constraints' => [
'name' => 'user_unique',
'columns' => [ 'username' ],
],
'indexes' => [
'name' => 'user_idx',
'clumns' => [ 'email' ],
],
'schema' => 'schema_name',
];
class User {}
?>
--
Richard "Fleshgrinder" Fussenegger
+1 for the basic idea, however, I have various remarks.
The RFC text is hard to read and contains many grammatical mistakes. How
could one help you here?
I would need a co-author :)
I think that the Hack name attributes is unintelligible and annotations
would be much clearer to any audience. Simply because the name is very
well known.
Different languages names this differently.
I may add an additional voting question - "annotation vs attributes?".
I do not see the need for multi-annotation nor multi-value support. It
just creates multiple ways to achieve the exact same thing for no good
reason.
completely disagree.
Each value in multi-value attribute may have its own meaning. e.g.
<<if(Condition,OnTrue,OnFalse)>>
I do not like the <<>> syntax. It requires many key strokes, is hard to
read, and looks ugly. Why not simply @ and be done with it. I am not so
sure about the bracket requirement, is it somehow required for the
parsing? Otherwise I would leave it off. I guess it might be hard to
find the end of an annotation but have you considered to use the
semicolon for that? Would align nicely with existing PHP syntax. The
following would be the ABNF for my proposal:ANNOTATION = "@" NAME [ " " VALUE ]
NAME = STRING
VALUE = QUOTED-STRING / PHP-CONSTANT / EXPRESSION
QUOTED-STRING = ( "'" / DQUOTE ) STRING ( "'" / DQUOTE )
EXPRESSION = PHP-CODE ";"A semicolon would only be required if it is not a single quoted string
(see following example) or constant. A question that I see unanswered is
how embedding of variables in quoted strings should be dealt with. I see
no need for this but people might assume it is supported because PHP
supports it everywhere else.<?php
$name = "Richard Fussenegger";
$email = "php@fleshgrinder.com";@author "{$name} <{$email}>"
class A {}<<author("{$name} <{$email}>")>>
class B {}?>
Requiring PHP code to be terminated with a semicolon should also ensure
that people do not start to write fully-fledged programs in annotations.
Since that is not what they are intended for. An alternative approach I
see here would be to go for the brackets but then again only for PHP code:EXPRESSION = "(" PHP-CODE ")"
Then again, it looks similar to a function call and this is imho not
good. Unless of course new annotations can be defined as special
functions directly in userland, e.g. with anannotation function
and/orannotation class
. However, this would require more thought.Another question that is unanswered for me is: how to go about adding
annotations to a complete file as is currently possible with PhpDoc and
its file-level doc block:<?php
@author 'Richard Fussenegger php@fleshgrinder.com'
@copyright '2016 Richard Fussenegger'
@license 'MIT'declare(strict_types=1);
namespace Fleshgrinder\PhpInternals;
@description 'True annotation support could be a very good thing.'
@invariant $this->balance >= self::MIN_BALANCE;
class Account {private const int MIN_BALANCE = 0;
private int $balance;
private Person $owner;
@require $sum >= 0;
@ensure $this->balance === (old::$balance + $sum);
public function deposit(int $sum): void {
$this->balance += $sum;
}@require $sum >= 0;
@require $sum <= $this->balance - self::MIN_BALANCE;
@ensure $this->balance === (old::$balance - $sum);
public function withdraw(int $sum): void {
$this->balance -= $sum;
}@deprecated 'for various reasons'
public function setOwner(Person $wner): void {
$this->owner = $owner;
}}
@inheritDoc
class OverdraftAccount extends Account {private const int MIN_BALANCE = -1000;
}
?>
You should try to implement this syntax to understand the problem.
It leads to parse conflicts.
We also need to make sure to add something regarding coding standards
for annotation names. I would propose to go for camelCase (same as for
method names) since this is what PhpDoc used to use for many years now.
This RFC is not going to propose coding standards.
We also need to define how people can avoid to collide with internal
annotations. The typical double-underscore prefix approach that we have
for magic methods creates a lot of visual clutter and looks weird if
spread among all kinds of places. A namespace approach as we have it
already for userland code could help here.<?php
use Doctrine\ORM;
@ORM::entity
@ORM::table [
'name' => 'user',
'unique_constraints' => [
'name' => 'user_unique',
'columns' => [ 'username' ],
],
'indexes' => [
'name' => 'user_idx',
'clumns' => [ 'email' ],
],
'schema' => 'schema_name',
];
class User {}?>
Agree. Namespaces looks better than "__" prefixes.
Thanks. Dmitry.
I think that the Hack name attributes is unintelligible and annotations
would be much clearer to any audience. Simply because the name is very
well known.Different languages names this differently.
I may add an additional voting question - "annotation vs attributes?".
The description on https://wiki.php.net/rfc even uses "annotation" to
explain what "PHP Attributes" is,
so I think "annotation"is the right naming choice.
PHP Attributes
Native support for annotation (Discussion began 2016-04-22)
Annotation is well known and unambiguous.
Regards, Niklas.
+1 for the basic idea, however, I have various remarks.
The RFC text is hard to read and contains many grammatical mistakes. How
could one help you here?
I would need a co-author :)
I would love to help you but would require some karma. I need to check
how to get it. I will answer more tomorrow.
--
Richard "Fleshgrinder" Fussenegger
completely disagree.
Each value in multi-value attribute may have its own meaning. e.g.
<<if(Condition,OnTrue,OnFalse)>>
That is a different example but I think that I misinterpreted it anyways.
<<test(1,2)>>
function foo() {}
I thought that the above would result in the following:
reflect foo => [
test => 1
test => 2
]
But I think in reality it results int:
reflect foo => [
test => [ 1, 2 ]
]
In case the latter is true, than everything is fine. :)
You should try to implement this syntax to understand the problem.
It leads to parse conflicts.
The inclusion of the semicolon definitely does, yes. Usage of the @
should not but Stanislav already offered to jump in. I am not fit enough
yet with the php-src to take up such a big challenge.
This RFC is not going to propose coding standards.
Only talking about a standard for internal attributes, userland can and
should do whatever they want. But we need to ensure consistency for
internal attributes and that userland is not going to collide with
internal ones.
Currently the RFC does not include any attributes but many examples that
others might use to deduce a coding standard and later we add internal
attributes and things go south.
--
Richard "Fleshgrinder" Fussenegger
Hi Dimitry,
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.
Nice RFC!
Attributes are always evaluated, right? i.e. No INI switch nor declare
to control behavior.
Just making sure.
Regards,
--
Yasuo Ohgaki
yohgaki@ohgaki.net
Hi Dimitry,
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.
Nice RFC!
Attributes are always evaluated, right? i.e. No INI switch nor declare
to control behavior.
Just making sure.
Attributes are always parsed together with PHP script and stored internally.
Then you may access them through Reflection*::getAttributes() or in C
extensions through native API.
AST in attribute values is not evaluated.
Thanks. Dmitry.
Regards,
--
Yasuo Ohgaki
yohgaki@ohgaki.net
I would like to present an RFC proposing support for native annotation.
Dmitry,
please use "annotation" as the name for this feature and not "attribute".
We already have attributes: it's what we use to store data in objects. And
while some people call them "member variables" or "properties" the correct
term for them (AFAIK) is "attribute".
Best,
Sebastian
-----Original Message-----
From: Sebastian Bergmann [mailto:sebastian@php.net]
Sent: Sunday, April 24, 2016 12:14 PM
To: internals@lists.php.net
Subject: Re: [PHP-DEV] [RFC] PHP AttributesI would like to present an RFC proposing support for native annotation.
Dmitry,
please use "annotation" as the name for this feature and not "attribute".
We already have attributes: it's what we use to store data in objects. And
while some people call them "member variables" or "properties" the correct
term for them (AFAIK) is "attribute".
I don't think I've ever heard properties referred to as attributes in the context of PHP. The PHP manual defines them and refers to them throughout as 'properties'.
(I'm not voicing an opinion on attributes vs. annotations; Just pointing out that data storage inside objects isn't named attributes).
Zeev
-----Original Message-----
From: Sebastian Bergmann [mailto:sebastian@php.net]
Sent: Sunday, April 24, 2016 12:14 PM
To: internals@lists.php.net
Subject: Re: [PHP-DEV] [RFC] PHP AttributesI would like to present an RFC proposing support for native annotation.
Dmitry,
please use "annotation" as the name for this feature and not "attribute".
We already have attributes: it's what we use to store data in objects. And
while some people call them "member variables" or "properties" the correct
term for them (AFAIK) is "attribute".I don't think I've ever heard properties referred to as attributes in the context of PHP. The PHP manual defines them and refers to them throughout as 'properties'.
(I'm not voicing an opinion on attributes vs. annotations; Just pointing out that data storage inside objects isn't named attributes).
Zeev
The terminology here is pretty clear and you can just look it up, it has
nothing to do with PHP or Java or whatever. The main problem is simply
that people do not know the terminology and get mixed up. That is
usually okay in a casual discussion where each peer understands what the
other is referring to. However, we are dealing with language
specification here and need to be very exact or we fuck it up for the users.
$x
is a property in the following example:
class A {
$x;
}
https://en.wikipedia.org/wiki/Property_%28programming%29
private
is an attribute of property $x
and an access modifier (not
visibility, because the property is still visible, e.g. via reflection,
and it only alters access to the property):
class A {
private $x;
}
https://en.wikipedia.org/wiki/Attribute_%28computing%29
Note that these things go further up in the terminology hierarchy to:
Field - https://en.wikipedia.org/wiki/Field_%28computer_science%29
Record - https://en.wikipedia.org/wiki/Record_%28computer_science%29
Data Structure - https://en.wikipedia.org/wiki/Data_structure
This is not the whole image yet, there are more things like (random order):
- functions
- methods
- members
- class variables
- static variables
- behavior
- data
- ...
You will notice, if you read all Wikipedia articles and related
documents, that these terms are too often used interchangeable. This is,
as mentioned before, mainly the case because people to not care about
terminology in general.
To sum it up, calling them attributes is outright wrong because not all
parts of a source code of a programming language has attributes. That is
why Sun chose the word annotation. Annotation means metadata that was
added to data. It does not say anything about the data itself and it
does not necessarily alter the data in any way, however, it can. This is
exactly what this feature is about. Since, an entity annotation does not
alter the data (in this case a class) itself but this additional
metadata may be used to configure other parts of the program.
The same is true for a method that has been annotated with test. The
data is not altered at all but is helps other parts of the program to
configure specific data and behavior based on this additional metadata
that was added to the data. Execution of the same method without those
other parts that react on the metadata does not do anything and the
program will execute normally.
TL;DR this feature MUST be called annotations (unless someone knows an
even better term) and the annotations MAY be used to add attributes to
properties but for many other things too.
--
Richard "Fleshgrinder" Fussenegger
-----Original Message-----
From: Sebastian Bergmann [mailto:sebastian@php.net]
Sent: Sunday, April 24, 2016 12:14 PM
To: internals@lists.php.net
Subject: Re: [PHP-DEV] [RFC] PHP AttributesI would like to present an RFC proposing support for native annotation.
Dmitry,
please use "annotation" as the name for this feature and not
"attribute".We already have attributes: it's what we use to store data in objects.
And
while some people call them "member variables" or "properties" the
correct
term for them (AFAIK) is "attribute".I don't think I've ever heard properties referred to as attributes in
the context of PHP. The PHP manual defines them and refers to them
throughout as 'properties'.(I'm not voicing an opinion on attributes vs. annotations; Just
pointing out that data storage inside objects isn't named attributes).Zeev
The terminology here is pretty clear and you can just look it up, it has
nothing to do with PHP or Java or whatever. The main problem is simply
that people do not know the terminology and get mixed up. That is
usually okay in a casual discussion where each peer understands what the
other is referring to. However, we are dealing with language
specification here and need to be very exact or we fuck it up for the
users.
$x
is a property in the following example:class A {
$x;
}https://en.wikipedia.org/wiki/Property_%28programming%29
private
is an attribute of property$x
and an access modifier (not
visibility, because the property is still visible, e.g. via reflection,
and it only alters access to the property):class A {
private $x;
}https://en.wikipedia.org/wiki/Attribute_%28computing%29
Note that these things go further up in the terminology hierarchy to:
Field - https://en.wikipedia.org/wiki/Field_%28computer_science%29
Record - https://en.wikipedia.org/wiki/Record_%28computer_science%29
Data Structure - https://en.wikipedia.org/wiki/Data_structureThis is not the whole image yet, there are more things like (random order):
- functions
- methods
- members
- class variables
- static variables
- behavior
- data
- ...
You will notice, if you read all Wikipedia articles and related
documents, that these terms are too often used interchangeable. This is,
as mentioned before, mainly the case because people to not care about
terminology in general.To sum it up, calling them attributes is outright wrong because not all
parts of a source code of a programming language has attributes. That is
why Sun chose the word annotation. Annotation means metadata that was
added to data. It does not say anything about the data itself and it
does not necessarily alter the data in any way, however, it can. This is
exactly what this feature is about. Since, an entity annotation does not
alter the data (in this case a class) itself but this additional
metadata may be used to configure other parts of the program.The same is true for a method that has been annotated with test. The
data is not altered at all but is helps other parts of the program to
configure specific data and behavior based on this additional metadata
that was added to the data. Execution of the same method without those
other parts that react on the metadata does not do anything and the
program will execute normally.TL;DR this feature MUST be called annotations (unless someone knows an
even better term) and the annotations MAY be used to add attributes to
properties but for many other things too.
The article you reference about attributes lists C# attributes as the
first example.
And defines an attribute as:
"For clarity, attributes should more correctly be considered metadata
https://en.wikipedia.org/wiki/Metadata. An attribute is frequently and
generally a property of a property."
HHVM uses the name attribute, for the same syntax that Dimitry proposes
here.
MUST is such a strong word in this context, this is not an 0 XOR 1 issue.
--
Richard "Fleshgrinder" Fussenegger
The article you reference about attributes lists C# attributes as the
first example.And defines an attribute as:
"For clarity, attributes should more correctly be considered metadata
https://en.wikipedia.org/wiki/Metadata. An attribute is frequently and
generally a property of a property."HHVM uses the name attribute, for the same syntax that Dimitry proposes
here.MUST is such a strong word in this context, this is not an 0 XOR 1 issue.
Thanks for the programming 101 lesson :)
I pointed out to Sebastian, who suggested that 'attributes' are
equivalent to 'member variables' or 'properties', that they're very
consistently referred to in PHP as 'properties' and that I'm not aware
that they were ever referred to as 'attributes'.Nothing in your links suggested otherwise, arguably the opposite.
According to https://en.wikipedia.org/wiki/Attribute_(computing), "An
attribute is frequently and generally a property of a property", and
while "the term attribute can and is often treated as equivalent to a
property depending on the technology being discussed", when the
technology in question is PHP, this is not the case.Of course, member visibility modifiers and access modifiers
(public/protected/private, static, etc.) are a different thing. Saying
member variables are referred to as attributes (incorrect in the context
of PHP, AFAIK) is very different from saying these modifiers are
referred to as attributes (correct and sensible).Last, we're absolutely allowed to have our own definitions of terms as
long as they're sensible. Both attributes and annotations are sensible
here, and the fact there may be languages that treat attributes as
equivalent to properties isn't a strong reason against using that term
for something sensible, that is different from these other languages, in
PHP.Zeev
As I said, unless somebody knows an even better term. It also depends on
which source code is going to be allowed to have this kind of additional
metadata. If we limit it to functions, classes, properties, and methods:
/all good./
Why?
We might want to allow adding of metadata to other parts of the source
code in the future. I already asked regarding annotating files
themselves (as is possible with PhpDoc's file-level docblock) and then
it becomes complicated. I am not saying we need this, I am saying we
need to clarify this.
Using the term attribute without defining what the term means is
problematic. I know, Facebook/HHVM/Hack but we are not required to be
compliant with them and they are not our benchmark.
Using the term annotation is not so problematic because it has a clear
definition (not only in computer science) and it does not say anything
about the applicability of what it does, it only states the
functionality of the feature itself: /adding metadata to data/.
You want to avoid writing extensive definitions of terms that are going
to be used since people then need to learn these terms. Just think about
the normal usage of the word attribute in language, e.g. describe the
attributes of this image. The answer could be "it shows a woman with
long hair and blue eyes". Hence, /long hair/ and /glue eyes/ are
attributes of the woman. However, asking for the annotations of this
image would result in a different answer, the asked person, assuming she
knows what the word in general means, turns the image and would tell us
the date and time it was taken or printed, or maybe the ISO level, ...
whatever.
Is public an attribute of the property? /Yes/
Is static an attribute of the method? /Yes/
Is name an attribute of a person? /Yes/
Is __toString an attribute of the class? /Yes, behavioral/
Is inattentive an attribute of the child? /Yes/
...
So, what should $r->getAttributes()
return? It is to broad, it is to
generic, it is too often mixed up.
$r->getAnnotations()
is less ambiguous in the context of programming
and thus a better choice.
I hope you can follow my /Gedankenspiel/ (mind game) better now. :)
--
Richard "Fleshgrinder" Fussenegger
Another way to illustrate what I mean:
The feature will be used /to annotate/ (add metadata) and the so
/annotated/ data has additional /attributes/ afterwards.
Trying building the sentence if the feature is called /attributes/.
@entity
@invariant
final class A {
@inject
private static $x;
@test
public memoized function f(){}
}
r = reflect A
r.getModifiers = [ final ]
r.getAnnotations = [ entity, invariant ]
r.getAttributes = [ final, entity, invariant ]
r = reflect A.x
r.getModifiers = [ private, static ]
r.getAnnotations = [ inject ]
r.getAttributes = [ private, static, inject ]
r = reflect A.f
r.getModifiers = [ public, memoized ]
r.getAnnotations = [ test ]
r.getAttributes = [ public, memoized, test ]
Note that there are programming languages that allow adding of metadata
solely via annotations: Ceylon. No matter the data to annotate. Hence,
in Ceylon no differentiation would be made between modifiers and
annotations. However, one could check the actual annotation type to
determine what it is.
--
Richard "Fleshgrinder" Fussenegger
Another way to illustrate what I mean:
The feature will be used /to annotate/ (add metadata) and the so
/annotated/ data has additional /attributes/ afterwards.Trying building the sentence if the feature is called /attributes/.
@entity
@invariant
final class A {@inject private static $x; @test public memoized function f(){}
}
r = reflect A
r.getModifiers = [ final ]
r.getAnnotations = [ entity, invariant ]
r.getAttributes = [ final, entity, invariant ]r = reflect A.x
r.getModifiers = [ private, static ]
r.getAnnotations = [ inject ]
r.getAttributes = [ private, static, inject ]r = reflect A.f
r.getModifiers = [ public, memoized ]
r.getAnnotations = [ test ]
r.getAttributes = [ public, memoized, test ]Note that there are programming languages that allow adding of metadata
solely via annotations: Ceylon. No matter the data to annotate. Hence,
in Ceylon no differentiation would be made between modifiers and
annotations. However, one could check the actual annotation type to
determine what it is.
The example isn't actually complete, sorry:
@entity
@invariant
final class A {
@inject
private static $x = 0;
@test
public memoized function f(){}
}
r = reflect A
r.getModifiers = [ final ]
r.getAnnotations = [ entity, invariant ]
r.getAttributes = [ final, entity, invariant, $x, f() ]
r = reflect A.x
r.getModifiers = [ private, static ]
r.getAnnotations = [ inject ]
r.getAttributes = [ private, static, inject, value((int) 0) ]
r = reflect A.f()
r.getModifiers = [ public, memoized ]
r.getAnnotations = [ test ]
r.getAttributes = [ public, memoized, test ]
I hope I didn't forgot any attribute. :P
All in all, attributes are things that things have to describe those
things and annotations allows us to add additional attributes to things,
on top of possible other attributes that are already addable by other
means (modifiers, values, ...).
--
Richard "Fleshgrinder" Fussenegger
-----Original Message-----
From: Fleshgrinder [mailto:php@fleshgrinder.com]
Sent: Sunday, April 24, 2016 2:49 PM
To: Zeev Suraski zeev@zend.com; Sebastian Bergmann
sebastian@php.net
Cc: internals@lists.php.net
Subject: Re: [PHP-DEV] [RFC] PHP Attributes-----Original Message-----
From: Sebastian Bergmann [mailto:sebastian@php.net]
Sent: Sunday, April 24, 2016 12:14 PM
To: internals@lists.php.net
Subject: Re: [PHP-DEV] [RFC] PHP AttributesI would like to present an RFC proposing support for native annotation.
Dmitry,
please use "annotation" as the name for this feature and not "attribute".
We already have attributes: it's what we use to store data in
objects. And while some people call them "member variables" or
"properties" the correct term for them (AFAIK) is "attribute".I don't think I've ever heard properties referred to as attributes in the
context of PHP. The PHP manual defines them and refers to them throughout
as 'properties'.(I'm not voicing an opinion on attributes vs. annotations; Just pointing out
that data storage inside objects isn't named attributes).Zeev
The terminology here is pretty clear and you can just look it up, it has nothing
to do with PHP or Java or whatever. The main problem is simply that people
do not know the terminology and get mixed up. That is usually okay in a
casual discussion where each peer understands what the other is referring to.
However, we are dealing with language specification here and need to be very
exact or we fuck it up for the users.
$x
is a property in the following example:class A {
$x;
}
Richard,
Thanks for the programming 101 lesson :)
I pointed out to Sebastian, who suggested that 'attributes' are equivalent to 'member variables' or 'properties', that they're very consistently referred to in PHP as 'properties' and that I'm not aware that they were ever referred to as 'attributes'.
Nothing in your links suggested otherwise, arguably the opposite. According to https://en.wikipedia.org/wiki/Attribute_(computing), "An attribute is frequently and generally a property of a property", and while "the term attribute can and is often treated as equivalent to a property depending on the technology being discussed", when the technology in question is PHP, this is not the case.
Of course, member visibility modifiers and access modifiers (public/protected/private, static, etc.) are a different thing. Saying member variables are referred to as attributes (incorrect in the context of PHP, AFAIK) is very different from saying these modifiers are referred to as attributes (correct and sensible).
Last, we're absolutely allowed to have our own definitions of terms as long as they're sensible. Both attributes and annotations are sensible here, and the fact there may be languages that treat attributes as equivalent to properties isn't a strong reason against using that term for something sensible, that is different from these other languages, in PHP.
Zeev
Hi,
I would like to present an RFC proposing support for native annotation.
Hi Dmitry,
Although everyone will have an opinion about the syntax, I think there
is one criticism that should be thought about; the chosen syntax isn't
future expandable to other concerns.
People have talked about "design by contract" RFCs where annotation
like data is readable by the engine. The current proposed syntax
could be used to store DBC data, but it would not be clear what
would be annotation data to read by the application, and what was DBC
data to be read by the engine.
Changing the proposed syntax to be something like @attr(...) would
allow it to be expanded in the future by adding a @contract(...)
construct:
@attr(test($a + $b > 0)) // This is attribute data read by userland code
@contract(require($a + $b > 0, 'InvalidFooArgsException')) // This is
DBC data read by the engine.
function foo($a, $b) {
...
}
Making features be compatible with future features would avoid a lot
of potential pain down the road.
cheers
Dan
Hi,
I would like to present an RFC proposing support for native annotation.
Hi Dmitry,
Although everyone will have an opinion about the syntax, I think there
is one criticism that should be thought about; the chosen syntax isn't
future expandable to other concerns.People have talked about "design by contract" RFCs where annotation
like data is readable by the engine. The current proposed syntax
could be used to store DBC data, but it would not be clear what
would be annotation data to read by the application, and what was DBC
data to be read by the engine.Changing the proposed syntax to be something like @attr(...) would
allow it to be expanded in the future by adding a @contract(...)
construct:@attr(test($a + $b > 0)) // This is attribute data read by userland code
@contract(require($a + $b > 0, 'InvalidFooArgsException')) // This is
DBC data read by the engine.
function foo($a, $b) {
...
}Making features be compatible with future features would avoid a lot
of potential pain down the road.
Genuine question[1]: how is @attr() different than <<attr()>>
? Also,
isn't @attr()
100% valid user-land code today that can precede
function or constant declarations?
[1] I don't like that I have to make that explicit but it is what it is.
Genuine question[1]: how is @attr() different than
<<attr()>>
? Also,
isn't@attr()
100% valid user-land code today that can precede
function or constant declarations?[1] I don't like that I have to make that explicit but it is what it is.
ROFL, that is actually totally true and I never thought about it. Damn
silencing operator! :P
However, i still think that the brackets are unnecessary and make it
look like function calls.
<<annotation values>>
function f() {}
--
Richard "Fleshgrinder" Fussenegger
Hey Levi,
TL:DR, if we can reserve some syntax for annotations that will be used
by the PHP Engine, that would cover my concern.
isn't
@attr()
100% valid user-land code today that can precede
Er, yes it is! I didn't put too much thought the suggestion. The point
I was trying to make is that it explicitly says that "this is a
userland attribute", rather than using the generic <<...>> syntax,
which we might want to use for non-userland attributes at some point.
how is @attr() different than
<<attr()>>
?
If this RFC passes, someone could implement their own DBC feature
using an annotation similar to:
<<dbc($a + $b > 0, 'InvalidFooArgsException')>>
Which under the current RFC proposal, would just be a standard
annotation as far the PHP Engine is concerned. The
framework/application the person is using would do the work to
implement the DBC feature in userland code.
In two years time when we want to implement dbc in the Engine, we
would need to choose between either:
-
using <<dbc(...)>> as the syntax for the PHP internal feature, which
would break userland code where they had chosen the same name we had. -
using a different syntax to the <<...>> one to implement a DBC feature.
-
think up a cunning way of adding to the <<...>> syntax that doesn't
break existing code that uses anotations.
Choosing a syntax now that can be expanded for other uses in the
future, is easier to do now, rather than in two years time, when it
would be a BC break.
Hack has implemented some 'special' attributes[1], that are
interpreted by the HHVM Engine. All of those special attributes start
with double underscores.
If we did the same, and reserved (through documentation), that
annotations starting with leading double underscores are reserved for
future expansion, that would allow us to implement them (if we wanted
to) without too many complaints of BC breakage.
i.e.
<<dbc(...)>> // this is a userland implementation
<<__dbc(...)>> // Reserved for PHP internal implementation.
cheers
Dan
Dan Ackroyd wrote on 24/04/2016 21:45:
The point
I was trying to make is that it explicitly says that "this is a
userland attribute", rather than using the generic <<...>> syntax,
which we might want to use for non-userland attributes at some point.
I think framing the problem as "engine vs userland" is misleading; what
you are actually saying is "how do we avoid name collisions?"
There's currently no difference in syntax between userland and engine
functions and classes, and that is a good thing, because it means you
can transparently apply polyfills, create C / Zephir extensions to
replace performance-sensitive functions, etc. The same could be done for
annotations - if it's possible to create a userland DBC library, then
why shouldn't it be able to polyfill the same syntax as an engine one?
As mentioned elsewhere, in an OO implementation of annotations, the
existing namespace hierarchy could be used (which includes the \php\
reservation, which we've never taken advantage of). If it's not, we are
left with naming conventions.
I would suggest that even if we don't have objects representing the
annotations, "" should be allowed, and encouraged, in their names.
Thus, by convention, attributes would be prefixed with at least a
vendor name ("<<Doctrine\Foo>>", etc).
PHP could reserve "__" and "php" for future internal use, but also
semi-reserve the global namespace, as described here:
http://php.net/manual/en/userlandnaming.rules.php
PHP owns the top-level namespace but tries to find decent descriptive
names and avoid any obvious clashes.
If somebody creates a userland library that uses <<DBC\Require(...)>>,
it's up to them to deal with the consequences if PHP later implements an
incompatible version, just as it would be if they wrote a function
called dbc_require(), or DBC::require().
Regards,
Rowan Collins
[IMSoP]
Hi,
I would like to present an RFC proposing support for native annotation.
Hi Dmitry,
Although everyone will have an opinion about the syntax, I think there
is one criticism that should be thought about; the chosen syntax isn't
future expandable to other concerns.People have talked about "design by contract" RFCs where annotation
like data is readable by the engine. The current proposed syntax
could be used to store DBC data, but it would not be clear what
would be annotation data to read by the application, and what was DBC
data to be read by the engine.Changing the proposed syntax to be something like @attr(...) would
allow it to be expanded in the future by adding a @contract(...)
construct:@attr(test($a + $b > 0)) // This is attribute data read by userland code
@contract(require($a + $b > 0, 'InvalidFooArgsException')) // This is
DBC data read by the engine.
function foo($a, $b) {
...
}Making features be compatible with future features would avoid a lot
of potential pain down the road.
Genuine question[1]: how is @attr() different than<<attr()>>
? Also,
isn't@attr()
100% valid user-land code today that can precede
function or constant declarations?
@attr() - is a valid "silenced" call to function named "attr".
This syntax can't be reused.
Thanks. Dmitry.
[1] I don't like that I have to make that explicit but it is what it is.
Hi!
@attr() - is a valid "silenced" call to function named "attr".
This syntax can't be reused.
Not valid if it's in the middle of class definition, and not valid in
form of:
@attr() function foo() { ... }
This is not a valid PHP syntax now. So I'm not sure why it can't be
used. << is an operator too and so is >> .
--
Stas Malyshev
smalyshev@gmail.com
Hi!
@attr() - is a valid "silenced" call to function named "attr".
This syntax can't be reused.
Not valid if it's in the middle of class definition, and not valid in
form of:@attr() function foo() { ... }
This is not a valid PHP syntax now. So I'm not sure why it can't be
used. << is an operator too and so is >> .
No, but this is valid:
@atrr(); function foo() { ... }
That's perhaps a little too close for comfort...?
Regards,
--
Rowan Collins
[IMSoP]
Hi!
No, but this is valid:
@atrr(); function foo() { ... }
That's perhaps a little too close for comfort...?
That's different syntax. If you put ; in the middle of statement, it can
change - "$c = $a + $b;" is not the same as "$c = $a; + $b;" - but
nobody thinks + can not be used because of that. As I said, << and >>
are existing operators too, so if you are creative enough, I'm sure you
can find cases like that too.
--
Stas Malyshev
smalyshev@gmail.com
Hi!
No, but this is valid:
@atrr(); function foo() { ... }
That's perhaps a little too close for comfort...?
That's different syntax. If you put ; in the middle of statement, it can
change - "$c = $a + $b;" is not the same as "$c = $a; + $b;" - but
nobody thinks + can not be used because of that. As I said, << and >>
are existing operators too, so if you are creative enough, I'm sure you
can find cases like that too.
Hi Stas,
You may try to replace attribute syntax with @attr(...) (without
semicolon) into our PHP parser.
Note that we have LALR grammar + restrictions caused by semantic actions.
If you are able to do this, I'll add it into the RFC as an option.
Thanks. Dmitry.
Hi!
You may try to replace attribute syntax with @attr(...) (without
semicolon) into our PHP parser.
Note that we have LALR grammar + restrictions caused by semantic actions.
If you are able to do this, I'll add it into the RFC as an option.
I'll try if I have time soon.
--
Stas Malyshev
smalyshev@gmail.com
Hi!
@attr() - is a valid "silenced" call to function named "attr".
This syntax can't be reused.
Not valid if it's in the middle of class definition, and not valid in
form of:@attr() function foo() { ... }
This is not a valid PHP syntax now. So I'm not sure why it can't be
used. << is an operator too and so is >> .No, but this is valid:
@atrr(); function foo() { ... }
That's perhaps a little too close for comfort...?
Regards,
Actually I agree with Stanislav (in pretty much every point he made so
far) on the syntax discussion, however, I already said that the brackets
are the main problem and it seems as it nobody sees it but your example
illustrates it perfectly.
@fopen('file', 'r'); function foo(){}
@deprecated function foo(){}
@throws InvalidArgumentException function foo(){}
@route ['name' => 'foo'] function foo(){}
Leaving out the brackets makes it very clear. I am in an extreme rush
and will read more in the thread the next days, sorry.
--
Richard "Fleshgrinder" Fussenegger
Hi,
I would like to present an RFC proposing support for native annotation.
Hi Dmitry,
Although everyone will have an opinion about the syntax, I think there
is one criticism that should be thought about; the chosen syntax isn't
future expandable to other concerns.People have talked about "design by contract" RFCs where annotation
like data is readable by the engine. The current proposed syntax
could be used to store DBC data, but it would not be clear what
would be annotation data to read by the application, and what was DBC
data to be read by the engine.Changing the proposed syntax to be something like @attr(...) would
allow it to be expanded in the future by adding a @contract(...)
construct:@attr(test($a + $b > 0)) // This is attribute data read by userland code
@contract(require($a + $b > 0, 'InvalidFooArgsException')) // This is
DBC data read by the engine.
function foo($a, $b) {
...
}Making features be compatible with future features would avoid a lot
of potential pain down the road.cheers
Dan
"@..." syntax can't work. @ - is a silence operator.
<<Contract\require($a + $b > 0, 'InvalidFooArgsException')>> - this is
not really worse than your example.
I know, any syntax is going to be loved by ones and hated by others...
It's not possible to satisfy everyone.
Thanks. Dmitry.
I know, any syntax is going to be loved by ones and hated by others...
It's not possible to satisfy everyone.
If one takes a step back, current well used annotation IS provided but
not cleanly documented in the docbloc material that is a major element
of legacy code. There is clearly a case for improving the usage of this
style of working, and adding 'attributes' to the rest of the rest of
this annotation seems to me to be the best way forward for a STOCK PHP
install. Every current IDE I've seen will correctly display docbloc
annotation and has the option to disable tags in that code if required.
I'm looking at the <?hh examples in hack and thinking that this is an
example of where an 'hack compatibility' extension to PHP may have a
place, but adoption some hack rules such as <<>> then imples that <?
code should work the same as <?hh code. That does not seem the right way
forward for users who have no intention to use hack and have no access
to it on their hosting? More important, and subtle differences will
cause even more problems? So can we not maintain a more flexible roadmap
that cherry picking other languages directly?
--
Lester Caine - G8HFL
Contact - http://lsces.co.uk/wiki/?page=contact
L.S.Caine Electronic Services - http://lsces.co.uk
EnquirySolve - http://enquirysolve.com/
Model Engineers Digital Workshop - http://medw.co.uk
Rainbow Digital Media - http://rainbowdigitalmedia.co.uk
Hi!
I've read the proposal and I like the idea of reviving the attributes
idea and the simplicity of the approach.
I have the following questions for it:
-
Namespacing. Since the attribute names are not processed in any way
according to spec, it may be rather hard to ensure attribute
requirements from different domains do not conflict, and we do not get
into the same problem we've got into with class names before we
implemented namespaces. How it is planned to address the issue? -
The expressions support is nice, however I'm not sure I understand
what PHP application is supposed to do with syntax trees? I.e. taking
the example in the RFC, if I got AST\Node representing <<test($a + $b >
0)>>, how do I use it? Would I implement mini-PHP-engine in PHP to
evaluate such an expression? Am I supposed to use some other
functionality to do it? It is unclear.
I don't think promoting reimplementing PHP expressions in a myriad of
different ways (which all would be subtly different and distinct from
how PHP understands such expressions) is not good, and if we expose
those trees we should also provide means to work with them. Otherwise
any advanced usage of the feature would mean basically reimplementing
PHP engine in PHP.
As a side note, my personal opinion is that for about 90% of use cases
expressions are not needed. For 90% of those which are needed, string +
some form of eval would cover it's use case since all the'd be doing is
evaluating the expression and checking the resulting value. -
As far as I can see, AST extension has no documentation except for
initial README. If it is going to end up in core, this needs to be
fixed. Preferably before it is merged into core. -
I would also consider moving AST namespace under \PHP since we have
this one reserved (unlike \AST which we did not reserve). -
Are attributes also allowed to apply to anonymous classes/functions?
Would the syntax still work in that case?
_ I also think <<...>> syntax is ugly and @attribute syntax would be
much better (and also is used in Java attributes and Python decorators).
That's my personal opinion though.
Thanks,
Stas Malyshev
smalyshev@gmail.com
Hi!
https://wiki.php.net/rfc/attributes
I've read the proposal and I like the idea of reviving the attributes
idea and the simplicity of the approach.I have the following questions for it:
- Namespacing. Since the attribute names are not processed in any way
according to spec, it may be rather hard to ensure attribute
requirements from different domains do not conflict, and we do not get
into the same problem we've got into with class names before we
implemented namespaces. How it is planned to address the issue?
I'm going to extend RFC with namespace support.
Attribute name is going to be qualified string.
- The expressions support is nice, however I'm not sure I understand
what PHP application is supposed to do with syntax trees? I.e. taking
the example in the RFC, if I got AST\Node representing <<test($a + $b >
0)>>, how do I use it? Would I implement mini-PHP-engine in PHP to
evaluate such an expression? Am I supposed to use some other
functionality to do it? It is unclear.
I don't think promoting reimplementing PHP expressions in a myriad of
different ways (which all would be subtly different and distinct from
how PHP understands such expressions) is not good, and if we expose
those trees we should also provide means to work with them. Otherwise
any advanced usage of the feature would mean basically reimplementing
PHP engine in PHP.
AST is going to be processed and evaluated using php-ast extension.
Nikita was going to propose including it into core distribution.
As a side note, my personal opinion is that for about 90% of use cases
expressions are not needed. For 90% of those which are needed, string +
some form of eval would cover it's use case since all the'd be doing is
evaluating the expression and checking the resulting value.
This is a question. We may use AST expression or just strings.
In second case we miss syntax verification at compile time.
I'm going to describe the problem in RFC and set an additional voting
question.
As far as I can see, AST extension has no documentation except for
initial README. If it is going to end up in core, this needs to be
fixed. Preferably before it is merged into core.I would also consider moving AST namespace under \PHP since we have
this one reserved (unlike \AST which we did not reserve).
For me AST is the best choice here.
- Are attributes also allowed to apply to anonymous classes/functions?
Would the syntax still work in that case?
No. At least now.
_ I also think <<...>> syntax is ugly and @attribute syntax would be
much better (and also is used in Java attributes and Python decorators).
That's my personal opinion though.
@ is reserved for silence operator.
Thanks. Dmitry.
Thanks,