On 04/22/2016 06:39 PM, guilhermebla...@gmail.com wrote:

On Fri, Apr 22, 2016 at 3:07 AM, Dmitry Stogov <dmi...@zend.com <mailto:dmi...@zend.com>> wrote:



    On 04/22/2016 04:05 AM, guilhermebla...@gmail.com
    <mailto:guilhermebla...@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 <dmi...@zend.com
    <mailto:dmi...@zend.com>> wrote:



        On 04/22/2016 02:16 AM, Dominic Grostate 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"
            <dmi...@zend.com <mailto:dmi...@zend.com>
            <mailto:dmi...@zend.com <mailto:dmi...@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

Reply via email to