Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:123124 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by qa.php.net (Postfix) with ESMTPS id 47AD51A009C for ; Fri, 12 Apr 2024 16:26:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1712939212; bh=qIrjFnUk6gjIINLkhJz+cyfp1G90fmxggyjPQQRPRgk=; h=In-Reply-To:References:Date:From:To:Subject:From; b=OCpqtWBA8QxpMbGXKYLE6/5soOaH0XESx5AZjp8RZifQNvGoGHX9HvNGe4KnOLjjp ovbXzf9o5O9aUQ29J/dkB3RYPBo5+aYkgPahvVB1h9jcRNnOJfspftWWkatiBdvfDW pBHyWOgu2qQDH7pFNhinR3iuJamPp4J4pFRGulK990lvGytw8+ndrCA5S1zNzUBuVR X5alNgTMmgDHd5U0a/19yar4ulJM04cDCeC5vdJ1MOpkA89ij4Ukudp/00tKmrK4vq 8mPoe0ZG0L8e0teQhScNcZMPoVqeJM/pQSxphRw0NK7lQzuu1b1EVjLbopOYUY9JMy DM7TxAI9L24AA== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 96E95180041 for ; Fri, 12 Apr 2024 16:26:51 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-0.1 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_MISSING,RCVD_IN_DNSWL_LOW, SPF_HELO_NONE,SPF_NONE,T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from wfout1-smtp.messagingengine.com (wfout1-smtp.messagingengine.com [64.147.123.144]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Fri, 12 Apr 2024 16:26:50 +0000 (UTC) Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailfout.west.internal (Postfix) with ESMTP id 09D671C0013A for ; Fri, 12 Apr 2024 12:26:14 -0400 (EDT) Received: from imap50 ([10.202.2.100]) by compute1.internal (MEProxy); Fri, 12 Apr 2024 12:26:15 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= garfieldtech.com; h=cc:content-type:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm2; t=1712939174; x= 1713025574; bh=3XJSKZntbSNY4JQg7dt74mjHyGg2sef9D62hUrPXjvo=; b=h XiejyrMzeE2k/7FwKyIrYj+D8V2g2GWZeuYIToSA97Vft8YGriIDSE+aIwnQtaW9 hrmM3p4XozxwBTfQshpHhZvnjukETbwFoRkN8CHXvMPZsjklM0N6DB7FKpAz7XUI h2tZgyrk+oLqhiH0VsIhHJi9yHfARXvcVD+h0wsa8lZB3GBCafn5UR9+V1/0JgjT pJu85zxCxc6WXhaYhU1IzpujStouWaiTUegZvKW6O7bw4zs25hvsyyEAq/WpMwb3 76qg43BKi8Ge1NidkmmKewaM3fLXNzftJm70UsZ+N0egNGvTG0oQj364sAGR6KA6 /MZf2qI+PBNCE+QrVIpQw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm2; t=1712939174; x=1713025574; bh=3XJSKZntbSNY4JQg7dt74mjHyGg2 sef9D62hUrPXjvo=; b=PAOayiPP6SQOQ11o47eTUVen6510gxGA/H/3YEg48uR8 GVXaxdSsAbvWZVan7seY3dx/BuFwO+Nzw1uVjJb+Rr35MOosfzDNbr0P3SKvOkwQ A08REAJgddLAy5SdGQ1M3zMOp8ckd031qsOJ3meEz7BPou8yICQCuA7TgyRqfjim KMZxMvPmgwS7MIxc5Xw6/dsg95qU+iQCx6nYCts8T3yJztMoHMeBK7x4PE14n6vu pI4bbUKUpGa/Wwn1mi2O3zQqI+eeSY1lLXt1G0U6VDaXRF5gaDUqEXqeLHKl1cYB L3/BixjqtsboeZhwARzShL4qdsy5bWLKpvSrEnQ+FQ== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvledrudeiuddguddtudcutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfgh necuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd enogfuuhhsphgvtghtffhomhgrihhnucdlgeelmdenucfjughrpefofgggkfgjfhffhffv ufgtsehttdertderredtnecuhfhrohhmpedfnfgrrhhrhicuifgrrhhfihgvlhgufdcuoe hlrghrrhihsehgrghrfhhivghlughtvggthhdrtghomheqnecuggftrfgrthhtvghrnhep ieevveeltedtjeektedtueefvdegjeegudehieetlefgvefgteejfffhveeugeeknecuff homhgrihhnpeefvheglhdrohhrghdpphhhphdrnhgvthenucevlhhushhtvghrufhiiigv pedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehlrghrrhihsehgrghrfhhivghlughtvg gthhdrtghomh X-ME-Proxy: Feedback-ID: i8414410d:Fastmail Received: by mailuser.nyi.internal (Postfix, from userid 501) id 2F4E11700093; Fri, 12 Apr 2024 12:26:14 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface User-Agent: Cyrus-JMAP/3.11.0-alpha0-379-gabd37849b7-fm-20240408.001-gabd37849 Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net MIME-Version: 1.0 Message-ID: <4f5865b5-6ffd-40f2-aa6e-756b8e3bb6f7@app.fastmail.com> In-Reply-To: <6618A2B1.70501@adviesenzo.nl> References: <66154AA0.1040905@adviesenzo.nl> <66160A1D.4060409@adviesenzo.nl> <6618A2B1.70501@adviesenzo.nl> Date: Fri, 12 Apr 2024 16:25:53 +0000 To: "php internals" Subject: Re: [PHP-DEV] [RFC][Vote announcement] Property hooks Content-Type: text/plain From: larry@garfieldtech.com ("Larry Garfield") On Fri, Apr 12, 2024, at 2:55 AM, Juliette Reinders Folmer wrote: > The first part of my email (up to the "Furthermore") was mostly me > trying to summarize the complexity of the proposal and to compare it to > existing syntaxes and list those things which - to me - appeared > inconsistent with other PHP features. It was not intended as criticism > on individual choices made and I'm not sure whether, if I were > designing this feature, I would have made different choices, other than > to have just one syntax - the "full" syntax (with a `get();`/`set();` > variant - yes, always with parentheses - for abstract/interface > properties). > > This first part was meant as a summation to highlight how incredibly > complex this new feature is and how many opportunities it offers > developers to shoot themselves in the foot. > Let alone, how many problems this can cause when developers use classes > in dependencies which use this new feature and they have limited to no > awareness of whether they are using virtual or backed properties on the > dependency. The RFC itself is complex because PHP is complex, and the problem space is complex. For instance, when hooks exist, what does that do for the return value of `=`? Most devs probably don't even remember that there is one, but as a language design element it has to be considered. Overall, the guiding design principle for this RFC was to make it as transparent as possible, so that devs who "use classes in dependencies which use this new feature and they have limited to no awareness of whether they are using virtual or backed properties on the dependency" do not need to care. The whole point is that it should be a transparent change, or as transparent as possible. Most of the complexity of the RFC is figuring out what the most transparent behavior would be, and ensuring that works. As indicated in the introduction, a primary use case for hooks is to not need to use them at all; 90%+ of all Doctrine entities I've seen have dumb boilerplate do-nothing get/set methods, placed there as a "just in case we need it" or "because That's How It's Done In Java Beans." Occasionally they do a little extra set validation, but not in the majority case. Hooks allow eliminating that "just in case" boilerplate. If hooks get almost no usage in the wild, but the option to use them eliminates hundreds of thousands of lines of effectively no-op getX() methods, I will consider it a resounding success. > As the proposal purports to be a better alternative to the magic > `_get()`/`__set()` methods, I would expect it to prevent a lot of the > problems associated with those methods. However, what I found - and > what you seemingly confirmed in your reply - is that this new feature > does *not* in actual fact solve the problems magic methods have. It has > the same problems + more problems associated with the new feature > itself. > > Part of my concern is therefore that this feature adds significant > extra complexity to the engine, for little to no real benefit, other > than to have a nicer syntax for creating the same problems we already > had before. I believe this is a highly disingenuous description of the RFC. * Hooks are automatically static-analysis-friendly. __get is not. * Hooks are automatically IDE autocomplete-friendly. __get is not. * Hooks provide built-in type enforcement. __get does not. * Hooks allow properties to be self-documenting. __get does not. * Hooks avoid smooshing multiple different virtual properties into a single mega-method. __get requires that. * Hooks allow opting-in to reference semantics per-property. __get is all-or-nothing. * Hooks have clear, consistent integration with serialization (in that the behavior with each serialization mechanism is consistent with that mechanism's expectations). __get doesn't interact with serialization at all, leaving you to do everything manually. * Hooks allow properties to be declared without special behavior, and add special behavior later without a BC break. __get... only kinda sorta does that, if you use it just right. * Hooks cleanly allow pre-defining properties to get the substantial memory savings of well-defined properties. __get may or may not, depending on how you impelement it. From a usability perspective, hooks are vastly superior to using __get/__set directly. However, both __get/__set and hooks operate in the same problem space: Inserting extra user-space code in between what otherwise seems like a boring variable read/write. *That* concept naturally involves complexity, by definition, and has lots of edge cases, by definition. Any attempt to insert user-space code into that operation would run into the exact same set of complexities; References exist, we have to deal with them somehow. `=` evaluates to a value, we have to deal with that somehow. Inheritance exists, we have to deal with that somehow. isset() exists, we have to deal with that somehow. This is all essential complexity. In most cases, we chose to address issues in the same way that __get/__set do precisely to keep it as simple as possible and reduce cognitive overhead for developers. The corner cases where the code insertion cannot be perfectly transparent already exist with __get/__set, and we therefore defaulted to "make them not-quite-transparent in the same way it's already not-quite-transparent," precisely to minimize the amount of thinking developers have to do. > In that sense, my email was not to ask you to make changes to the > proposal [*], but far more to try and make sure that those people with > the power to vote and without the time to fully read and really grep > the (really really long) proposal, are put in a position to make an > informed choice. Given the extensive feedback the RFC has gotten, both on list and off, I am confident that those who care to understand the level of complexity already do. > [*] The part after the "Furthermore" did contain some criticism, where > my points marked with [2] and [3] are AFAICS just a matter of > clarifying things in the RFC, while [1] and [4] would possibly warrant > changes, though I would expect (hope) the impact of those in dev time > to be small. > Oh and yes, my remark about `var` would also warrant a change in the > RFC text. > > I can see that those textual changes in the RFC have been made in the > mean time, so thank you for adding the additional clarifications for > those points to the RFC. And we appreciate you calling out those inconsistencies. We just wish you had done so 6 weeks ago, when it could certainly have been done in a polite and constructive way, as you said you wanted to do. >>> [4] Why should ReflectionProperty::getRawValue() throw an error for static properties ? Instead of returning the value, identically to ReflectionProperty::getValue() ? This is surprising to me and I see no reason for it. >> Because it's equivalent to `getValue`, and indicates the user is doing >> something they don't fully understand. > Except that it isn't equivalent behaviour, as `getValue()` will return > the value for both static and non-static properties without any > problems. > See: https://3v4l.org/v4F0S which is based on Example #1 in the > documentation of > https://www.php.net/manual/en/reflectionproperty.getvalue.php Static properties have no concept of virtual or backed values, so anyone calling getRawValue() on a static property is already doing something illogical. That said, if in practice we find this is problematic it is trivial to relax the throw to it being a pure alias of getValue() in the future; tightening it up in the future would be a BC break. > Forgive me, but I had to chuckle at the mention of virtual properties > needing to access a dynamic property in the context of a property guard. > My thoughts went straight to the following question "Does this mean > that support for dynamic properties could never be removed if this RFC > gets voted in ? And if so, can we please get rid of the deprecation > notice (and need for the attribute) ?" As noted above, this was simply "what do __get/__set do?", which in some cases would result in a dynamic property. Whether that is wise or not is a different question. Based on this thread we've decided that there are no good use cases for this pathway, so we're going to deviate from __get/__set in this instance. This is the text I just added to the RFC (in the Scoping section): If a hook calls a method that in turn tries to read or write from the property again, that would normally result in an infinite loop. To prevent that, accessing the backing value of a property from a method called from a hook on that property will throw an Error. That is somewhat different than the existing behavior of __get and __set, where such sub-called methods would bypass the magic methods. However, as valid use cases for such circular logic are difficult to identify and there is added risk of confusion with dynamic properties, we have elected to simply block that access entirely. > I'll try to give you some idea, though I fear this is not really PHP > Internals mailinglist material as it is a bit too detailed and too > specific to one tool. I am going to skip the weeds of the PHPCS implementation, and just ask you, and everyone, to provide this kind of feedback on future RFCs early, not at the literal last minute when everything was already polished. If there are small tweaks to the syntax that would have made user-space meta tools (formatters, SA tools, etc.) substantially easier, that's something we would have been open to hearing 8 weeks ago, or a year ago when this was first proposed. Addressing it now would require non-trivial design work from us, non-trivial implementation changes from Ilija, and non-trivial discussion and review from the half-dozen or so other reviewers that have taken an active interest in this RFC (which we very much appreciate!). Trying to do that now would burn several weeks more time, with only one person involved being paid for it (Ilija works for the Foundation), and like every RFC it's all still spec work. Even if you're not sure how to make it "polite", provide that kind of feedback early and often, in bite-sized pieces, so that it can save everyone's time, including yours. This is a major structural failing of the current RFC process, something many have pointed out already. It desperately needs to be addressed. Until it does, though, there are ways we can make the process at least a little less painful for all involved. --Larry Garfield