Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:92735 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 51128 invoked from network); 25 Apr 2016 15:24:37 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 25 Apr 2016 15:24:37 -0000 Authentication-Results: pb1.pair.com header.from=dmitry@zend.com; sender-id=pass Authentication-Results: pb1.pair.com smtp.mail=dmitry@zend.com; spf=pass; sender-id=pass Received-SPF: pass (pb1.pair.com: domain zend.com designates 207.46.100.118 as permitted sender) X-PHP-List-Original-Sender: dmitry@zend.com X-Host-Fingerprint: 207.46.100.118 mail-by2on0118.outbound.protection.outlook.com Received: from [207.46.100.118] ([207.46.100.118:3360] helo=na01-by2-obe.outbound.protection.outlook.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 48/39-00233-4B63E175 for ; Mon, 25 Apr 2016 11:24:36 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=RWSoftware.onmicrosoft.com; s=selector1-zend-com; h=From:To:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=F9Pu9e3CZZBsrNnmW+y/45JTqnuqHAj0OvuNT5+6MiI=; b=NGba2M7Jb7Rj8RoDwX8ihRhyV1LKgA3tteuWVZwJNzK2iGtU3sjJZyuzxE+6GUVqBy5nsgZt1oyX5/LVBLMd5JX0SqP5mOCkRmt9tTHM9mtZqrbX08GSUG1WpLDf9JppD63AzDnlQmPjEnwpq7ASzuCJkO6ZJw/uyjCDMDELUYc= Received: from BY2PR0201MB1784.namprd02.prod.outlook.com (10.163.72.26) by BY2PR0201MB1781.namprd02.prod.outlook.com (10.163.72.23) with Microsoft SMTP Server (TLS) id 15.1.466.19; Mon, 25 Apr 2016 15:24:31 +0000 Received: from BY2PR0201MB1784.namprd02.prod.outlook.com ([10.163.72.26]) by BY2PR0201MB1784.namprd02.prod.outlook.com ([10.163.72.26]) with mapi id 15.01.0466.025; Mon, 25 Apr 2016 15:24:31 +0000 To: "guilhermeblanco@gmail.com" CC: Dominic Grostate , PHP internals Thread-Topic: [PHP-DEV] [RFC] PHP Attributes Thread-Index: AQHRnBAun0yJJJCyoUaLowSO4sZVN5+VD36AgAA6G4D//+SGAIAAl08AgABc3QCABGPuAIAAOnMAgAADAYCAABCl+Q== Date: Mon, 25 Apr 2016 15:24:31 +0000 Message-ID: References: <571965D1.9020102@zend.com> <5719CDB2.90103@zend.com> <571DCA6A.2070803@zend.com> , In-Reply-To: Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: authentication-results: googlemail.com; dkim=none (message not signed) header.d=none;googlemail.com; dmarc=none action=none header.from=zend.com; x-originating-ip: [92.62.57.172] x-ms-office365-filtering-correlation-id: e4a8f62a-a943-482b-6743-08d36d1db338 x-microsoft-exchange-diagnostics: 1;BY2PR0201MB1781;5:2EYGPfKASGP81nyGyuXT5w4MPcPmNIhhzmxO7wT2nnr3ASOWOFRx4e59j98N2v0UxRYw7IgaElF4Wz8oyAaMlkqTpZsKOYMVvYxriaEC0b4QIf+AWB5WrrTKTC6bvPaCbqcB9zn8WaZNcuhlugsDm1TAjrZD/tQk5oMLVelhm7gC89SRxYz1vDV2PLPr++ac;24:TkMy1WdkUKXWHrKWgnaO+Vv4ha9sSSLMR8ePggNZa4q83YROoTvlFYhgNj9zHUB+s23Q8Fv3SFCu17z8I4Zhd+BWOZEmaD0oc1wY+MdVmF0=;7:aGylC+58u//+0rYm9n5qc277TzBhZldXZMAmGeUhWKVQltzrjDf5cgfwlacwZ4G9vj4K3o8yzH8XuZKPONL0j60wSbT8cot+yrKN9tiVTGUQ448whDzOuSM7pQvU+tMfj5cRBLtqF7vuPhjhWAAxe4Q8XGRn8nxOWzFLAl+XK2xHK5ljJzn39c/99fY6Gc73tG5YchJ5/uE8u/akw0EYyNI12hyTuJxIMNTcYR0mf3w= x-microsoft-antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BY2PR0201MB1781; x-microsoft-antispam-prvs: x-exchange-antispam-report-test: UriScan:; x-exchange-antispam-report-cfa-test: BCL:0;PCL:0;RULEID:(9101521026)(601004)(2401047)(8121501046)(5005006)(3002001)(10201501046);SRVR:BY2PR0201MB1781;BCL:0;PCL:0;RULEID:;SRVR:BY2PR0201MB1781; x-forefront-prvs: 0923977CCA x-forefront-antispam-report: SFV:NSPM;SFS:(10019020)(979002)(24454002)(377454003)(2906002)(81166005)(5640700001)(5002640100001)(2501003)(9686002)(5003600100002)(74316001)(86362001)(33656002)(561944003)(2950100001)(19625215002)(3900700001)(77096005)(15395725005)(16236675004)(19627405001)(2900100001)(16297215004)(15975445007)(50986999)(76176999)(54356999)(3280700002)(122556002)(3660700001)(19617315012)(10400500002)(189998001)(2351001)(110136002)(87936001)(66066001)(99286002)(76576001)(92566002)(1730700002)(4326007)(93886004)(106116001)(19580405001)(102836003)(19580395003)(586003)(1096002)(1411001)(1220700001)(6116002)(3846002)(5008740100001)(5004730100002)(11100500001)(969003)(989001)(999001)(1009001)(1019001);DIR:OUT;SFP:1102;SCL:1;SRVR:BY2PR0201MB1781;H:BY2PR0201MB1784.namprd02.prod.outlook.com;FPR:;SPF:None;MLV:ovrnspm;PTR:InfoNoRecords;LANG:en; spamdiagnosticoutput: 1:23 spamdiagnosticmetadata: NSPM Content-Type: multipart/alternative; boundary="_000_BY2PR0201MB1784BEC51CEE327F75CE09E4BF620BY2PR0201MB1784_" MIME-Version: 1.0 X-OriginatorOrg: zend.com X-MS-Exchange-CrossTenant-originalarrivaltime: 25 Apr 2016 15:24:31.4700 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 32210298-c08b-4829-8097-6b12c025a892 X-MS-Exchange-Transport-CrossTenantHeadersStamped: BY2PR0201MB1781 Subject: Re: [PHP-DEV] [RFC] PHP Attributes From: dmitry@zend.com (Dmitry Stogov) --_000_BY2PR0201MB1784BEC51CEE327F75CE09E4BF620BY2PR0201MB1784_ Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable This is another reason to use PHP layer on top on base attribute functional= ity. Implementing caching would take just 3 additional lines of PHP code. ________________________________ From: guilhermeblanco@gmail.com Sent: Monday, April 25, 2016 17:22 To: Dmitry Stogov Cc: Dominic Grostate; PHP internals Subject: Re: [PHP-DEV] [RFC] PHP Attributes Another thing that looks odd to me i that every time you call new Reflectio= nClass, 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 > wrote: On Mon, Apr 25, 2016 at 3:42 AM, Dmitry Stogov > wrote: On 04/22/2016 06:39 PM, guilhermeblanco@gmail.com wrote: On Fri, Apr 22, 2016 at 3:07 AM, Dmitry Stogov > 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 unde= rstand this feature implementation requires several design decisions and al= so 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" implement= ation 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 t= hem have some common demands, like lazy initialization of metadata. Here th= ey 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 mo= re robust implementation demands. - Robust approach: language takes the burden of instantiating complex struc= tures, validating, assertion of valid keys, values, if this complex structu= re 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 compilatio= n - 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 mentione= d that both approaches require lazy-initialization (which means, whenever y= ou 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 instantia= te objects or call functions. You already demonstrated interest to support = <> reusing the imports (which is our biggest headache in Doctri= ne Annotations), so why not issue constructor or function calls there? That= would simplify the work needed for consumers and also add room for later i= mprovements. So basically in this example: use Doctrine\ORM; <> class User {} $reflClass =3D new \ReflectionClass("User"); var_dump($reflClass->getAttributes()); We'd be changing from this: array(1) { ["Doctrine\ORM\Entity"]=3D> array(1) { [0]=3D> string(4) "user" } } Into this: array(1) { ["Doctrine\ORM\Entity"]=3D> object(Doctrine\ORM\Entity)#1 (1) { ["tableName"]=3D> string(4) "user" } } As I showed already, it's very easy to do this transformation at higher lay= er. $reflClass =3D new \ReflectionClass("User"); $attributes =3D $reflClass->getAttributes() foreach ($attributes as $key =3D> &$val) { $val =3D 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, s= tatic method or constructor, you actually add whole new level of possibilit= ies, and I fail to see which limitations are added. Could you provide me on= e? Calling the function/constructor/static method, not only helps to better se= gregate userland code, but it also adds subsequents extensibility. I can hi= ghlight 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, me= thod or property. We use this extensively in Doctrine, where you cannot def= ine 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 annotat= ions being used and override DO_FCALL to call before, after or around throu= gh the implementation of interfaces. - If we ever decide to support named parameters, taking advantage of that w= ould become natural, like: < "user")>> 1- Your approach is basically defining an array. Could you explain your lin= e of thinking on why you didn't consider a syntax like the one below? <["key" =3D> "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 def= ine 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 prop= erties. According to the RFC, getAttributes() was added over ReflectionFunc= tion. Is there a reason why support was not added to methods (ReflectionMet= hod extends ReflectionFunctionAbstract, which was not mentioned on RFC)? An= y 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 Reflecti= onParameter. Example: class Foo { public function bar(<> Bar $bar) : bool { // ... } } $reflClass =3D new \ReflectionClas("Foo"); $reflMethod =3D $reflClass->getMethod("bar"); $reflParameter =3D $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 happe= ns in Symfony2 through their "extra" bundle (doc: http://symfony.com/doc/cu= rrent/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. Examp= le: class UserController extends Controller { public function viewAction(<> User $u= ser =3D null) { if ($user =3D=3D=3D null) { throw new NotFoundException("User not found"); } return ["me" =3D> $this->getUser(), "user" =3D> $user]; } } 3- Did you put any thought on inheritance? What I mentioned in comment #1 i= s even smaller than what you implemented in RFC. Assuming you keep the RFC approach, did you consider support overrides, inh= erit, 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 attribute= s. This leads to some serious copy/paste, highly error prone... =3D( Another example is like we do in Doctrine. We support a callback system whi= ch we named as lifetime callbacks. Pre-persist is one of them, which is cal= led 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. Ex= ample: use Doctrine\ORM; trait Timestampable { protected $created; protected $updated; <> public function prePersist() { $this->created =3D $this->updated =3D new \DateTime("now"); } <> public function preUpdate() { $this->updated =3D new \DateTime("now"); } } <> class User { use Timestampable; public function prePersist() { // Add my custom logic } } The implication is that through a simplistic approach, inheriting (or overr= iding) 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 mention= ed before, then we could easily build structures like __Inherit, __Override= , etc. It's definitely, not clear when attribute inheritance make sense and when c= ompletely 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 i= nheritance at all. The higher layers may emulate "inheritance" of some attr= ibutes their selves (like you do this with doc-comments). As I said earlier, if you do a call based approach, we could create @Inheri= t or @Override, which would not only make us safe from support, but also gi= ves 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 pe= rform 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 cal= led that is annotated as <>, I would like to issue an E_USER_DE= PRECATED warning. A trigger-like solution would be required. Did this conce= pt 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 the= m. Especially, for your use-case: 1) it's possible to create preprocessor that embeds corresponding trigger_e= rror() call 2) it's possible to write a PHP extension that plugs-into compiler chain an= d checks <> attribute for each compiles function, then sets ZEN= D_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 thi= s. However, taking a more robust approach would potentially open this possibil= ity 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= try@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 ass= ertions ourselves, as opposed to requiring it within the language. this was the idea - to give a good tool instead of implementing every possi= ble 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 PH= P 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" >> 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 -- Guilherme Blanco Lead Architect at E-Block --_000_BY2PR0201MB1784BEC51CEE327F75CE09E4BF620BY2PR0201MB1784_--