Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:94308 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 77680 invoked from network); 28 Jun 2016 17:24:16 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 28 Jun 2016 17:24:16 -0000 Authentication-Results: pb1.pair.com header.from=php@fleshgrinder.com; sender-id=unknown Authentication-Results: pb1.pair.com smtp.mail=php@fleshgrinder.com; spf=permerror; sender-id=unknown Received-SPF: error (pb1.pair.com: domain fleshgrinder.com from 77.244.243.84 cause and error) X-PHP-List-Original-Sender: php@fleshgrinder.com X-Host-Fingerprint: 77.244.243.84 mx103.easyname.com Received: from [77.244.243.84] ([77.244.243.84:56171] helo=mx202.easyname.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 63/C5-41838-FB2B2775 for ; Tue, 28 Jun 2016 13:24:16 -0400 Received: from cable-81-173-134-219.netcologne.de ([81.173.134.219] helo=[192.168.178.20]) by mx.easyname.com with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.84_2) (envelope-from ) id 1bHwk8-0001FE-F6; Tue, 28 Jun 2016 17:24:12 +0000 Reply-To: internals@lists.php.net References: <211db59e-9c22-6df4-1f72-66ebbc5095bd@fleshgrinder.com> To: Rasmus Schultz , Pedro Cordeiro Cc: Marco Pivetta , PHP internals Message-ID: <09d63c5e-c5e9-5c7a-b28c-beab7dd5b972@fleshgrinder.com> Date: Tue, 28 Jun 2016 19:24:02 +0200 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:45.0) Gecko/20100101 Thunderbird/45.1.1 MIME-Version: 1.0 In-Reply-To: Content-Type: multipart/signed; micalg=pgp-sha256; protocol="application/pgp-signature"; boundary="DVncwrw8c5eaJSHod82UgkiL0lqiR2eFr" X-ACL-Warn: X-DNSBL-BARRACUDACENTRAL Subject: Re: [PHP-DEV] [RFC] Simple Annotations From: php@fleshgrinder.com (Fleshgrinder) --DVncwrw8c5eaJSHod82UgkiL0lqiR2eFr Content-Type: multipart/mixed; boundary="DKJA4WPRoCKrusVMUj2xl94GV9RBNPi0h" From: Fleshgrinder Reply-To: internals@lists.php.net To: Rasmus Schultz , Pedro Cordeiro Cc: Marco Pivetta , PHP internals Message-ID: <09d63c5e-c5e9-5c7a-b28c-beab7dd5b972@fleshgrinder.com> Subject: Re: [PHP-DEV] [RFC] Simple Annotations References: <211db59e-9c22-6df4-1f72-66ebbc5095bd@fleshgrinder.com> In-Reply-To: --DKJA4WPRoCKrusVMUj2xl94GV9RBNPi0h Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable On 6/28/2016 6:31 PM, Rasmus Schultz wrote: > Since the discussion isn't completely dead yet (thank you Pedro and > Marco), I will just briefly explain what I had in mind for another > RFC. >=20 I want to see this feature happen too but the right way, so let us just spend some more time wrapping our heads around it. We could also discuss and work on the RFC at a different place (GitHub with issues?), since many people are always complaining about too many emails that are sent to this ML. On 6/28/2016 6:31 PM, Rasmus Schultz wrote: > The syntax would no longer allow arbitrary expressions - instead, it > would allow object annotations only, declared in one of three ways: >=20 > << RequiresLogin >> // equivalent to new RequiresLogin() >=20 > << Length(20) >> // equivalent to new Length(20) >=20 > << HttpMethod::post() >> // equivalent to static method-call HttpMethod= ::post() >=20 > The latter permits you to declare and call static factory methods, > e.g. "named constructors" for some types of annotations. >=20 > Annotations are now consistently objects, which simplifies filtering > annotations, etc. >=20 > This declaration syntax enables better in-language analysis - because > the declarations always include the annotation class-name, this means > it can now support deferred as well as conditional creation, by having > a slightly different reflection API: >=20 > $annotations =3D $class_reflection->getAnnotations(); >=20 > At this point, we have a list of ReflectionAnnotation objects - the > actual annotation objects have *not* been created at this point, which > would allow for conditional evaluation, such as: >=20 > foreach ($annotations as $annotation) { > echo $annotation->className; // =3D> "Length" etc. >=20 > if ($annotation->classExists()) { > var_dump($annotation->getInstance()); // =3D> Length object= , etc. > } else { > var_dump($annotation->getInstance()); // =3D> UnknownAnnota= tion object > } > } >=20 > The UnknownAnnotation object has three properties: class-name, > method-name ("__construct" if constructor was used) and the list of > arguments. >=20 > In other words, this would provide support for "optional > dependencies", in much the same way that unserialize() does it - the > getInstance() method will trigger autoloading, and if the class is > unavailable, it takes this "typeless" information and puts it in a > general object, so that the information itself isn't lost. >=20 Awesome! This is exactly the kind of thing that one wants from reflection, information and not exceptions or worse. :) On 6/28/2016 6:31 PM, Rasmus Schultz wrote: > It may *seem* like this solves the optional dependency problem, but > let me be clear, it does *not* fully address that issue, because > something like << Method(Http::GET) >> could still fail, if the Method > class is defined, but the Http class is not. That's a much more > marginal case, but it's not completely unlikely that you would use > constants from one dependency and pass them to annotation classes from > another dependency, e.g. if the HTTP method constants were part of an > HTTP package, and the annotation itself were part of a different > package. Arguably it's much less likely to occur though - if you have > the annotation package installed, most likely you have the dependent > package of that package installed as well. >=20 > So this is much safer, but just to be clear, the only way you can make > it any safer than that, is by completely disallowing anything but > values as arguments to annotation constructors - which, in my opinion, > simply isn't useful. >=20 I would argue that this should fail if the Method class from the example exists and is actually being created. However, if the Method class does not exist (and we construct an UnknownAnnotation stub for it) nothing should go wrong. I mean, the assumption that the dependency of a missing dependency is/might be missing sounds logical too me. Of course we would need to have something like an UnknownAnnotationArgument stub too. Note that this allows you in consequence to create other kinds of objects within annotations: << Annotation(new Argument) >> final class {} This would allow nesting as some DocBlock libraries allow it currently. On 6/28/2016 6:31 PM, Rasmus Schultz wrote: > Alternatively to the above, you could imagine a simpler reflection > facility that does eagerly construct annotations, but constructs > UnknownAnnotation instances for missing classes - this would perhaps > balance more towards immediate usefulness and less towards performance > perfectionism, as it increases the chance of loading an unused > annotation. >=20 > This would be my preference though - as previously argued, the odds of > having a large number of unrelated annotations on the same member are > extremely low in practice; an annotated entity tends to be a persisted > property, a form input element, or an action method, etc... rarely do > you mix annotations from different domains onto the same member; > annotations that are applicable to a given domain are usually relevant > to a consumer belonging to the same (or a closely related) domain, so > this performance concern is mostly a theoretical micro optimization. >=20 > For another, eager construction means we can filter annotations with > instanceof rather than by class-name, which is much powerful, enabling > you to leverage inheritance - for example, you'd be able to ask > directly for all instances of ValidationAnnotation and get those with > a single call, which is incredibly useful. >=20 Isn't it possible to go for a generator (yield) like approach and combine the best of both worlds? That being said, I am in favor of this approach as well, because, as you said, instanceof is more powerful and one expects all annotations to be present, the UnknownAnnotation would be a special case. On 6/28/2016 6:31 PM, Rasmus Schultz wrote: > Anyways, let me know your feelings about that idea? If there's any > interest, I'd be happy to write yet another RFC based on that. >=20 +1 with one thing, go for the @ and not <<>>. It is possible with the parser and so far most people stated that they prefer it, or put it to vote with a separate poll. @Route('/blog/{id}', new Method(Http::GET)) @ParamConverter('post', Post::class) public function indexAction(Post $post) {} --=20 Richard "Fleshgrinder" Fussenegger --DKJA4WPRoCKrusVMUj2xl94GV9RBNPi0h-- --DVncwrw8c5eaJSHod82UgkiL0lqiR2eFr Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAEBCAAGBQJXcrK2AAoJEOKkKcqFPVVrITQP/1Lz6U6Ypn/wmIVt1+1WUIpo LRlsa2iouAssYUoQ77iZJa2TKfapMqraI1VZ9lgPoUDQ5Xjw8Xwut7sqMklfoYwd Y1vBLO7cX052ho2nwoCGzaZb4uhCftY+k3+H+2sQKRuP/SzSF9xRBGaO4G8IScLt grQomPvNLfLDEFK4/VUNP/Q8O1HxeAVAQr8m9+citGFt6n90TU4F5voXM2yuCe/u +ABvesqcd6dhdFDB6s8z0jRWETehfHsFfUVBFj+x8Mp9nofKQXhPIkaYshYzWwho 02nXEJCPI5TN2Iu1w9zGxfx5E2Uh6qUwWauO0lN+L4w9fAQg1lwO5eITJDS4TTiN uubuZsItblaGMj5+owM63eJ4h8UDoK4hu9AsBmSe9DG38B7MVaGRCfBqYTCNkGt3 M0lR6Y3NU/rg2l71ivDJaADdxkF+UcGIdxFTdyx84ifOAG8oqVhoG7Keab0DCTp8 eo8/fq/aLkN6ln9hTaAq4BUHcehefLdlLOkPSe3l8aN5WY415azCkumPnFJpJSim b9kxv0RgDBde53arsRhsdAXrSaw6pilDumQoCq/gTRBCryryzcfhBdWe5uneiGE8 ZYC+zkFeY+YFNRR94mHDlqTE9UGv5eGbv4RUHu7TTpPE2RO3VWhBTlot3+1WdcpH UMo9eLItyQcAgPnVPe+3 =e9mw -----END PGP SIGNATURE----- --DVncwrw8c5eaJSHod82UgkiL0lqiR2eFr--