Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:122628 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 90ED31AD8F6 for ; Tue, 12 Mar 2024 22:44:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1710283469; bh=ojTHkSHZtpKEi/ofkVSH9U4v1inepEjvUhr7YMcAEWk=; h=In-Reply-To:References:Date:From:To:Subject:From; b=J2oYu+QWepkCmyYWko0D0ByjMBL7zvXaQiusvls/ADpl8LnpnxXzpV9zjxOQNu35v qvT6SpTjOZzcdkOgQSFVxZ8/eDxGr36Y+OLEzTn1BJ/GdM2XWOVJBrQt+mgN5ArRYB K0JsGFSt/le+TX1rmAvXWX+h577YowPifXkmHXeuo7ZKBd8HCXtVExOqzZB7fBN9+b jCk7rTUAfaqTZq19b1cmTlWZs8qZqy56nYXrhMSxfvlwjGRWyjxIO1LEB42gvdjOqz G9KRBWnAYqdZhX94tTanN46GHpqzTkT1sUdrO00A/BoPYEP03J5zwus3knFBLaoSVm 3T0Fw7lT+0sIw== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 7B82A180087 for ; Tue, 12 Mar 2024 22:44:27 +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.9 required=5.0 tests=BAYES_40,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_MISSING,RCVD_IN_DNSWL_LOW, SPF_HELO_PASS,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 wout5-smtp.messagingengine.com (wout5-smtp.messagingengine.com [64.147.123.21]) (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 ; Tue, 12 Mar 2024 22:44:26 +0000 (UTC) Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailout.west.internal (Postfix) with ESMTP id 4B83E32009F4 for ; Tue, 12 Mar 2024 18:44:09 -0400 (EDT) Received: from imap50 ([10.202.2.100]) by compute1.internal (MEProxy); Tue, 12 Mar 2024 18:44:09 -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=fm1; t=1710283448; x= 1710369848; bh=Y0234bVBwqUQILBnapCT6OCSyEWmNQKMGcosq+eMbhU=; b=T /pouY7QHU2jKdOXC8T7JRUQXQrHHdPoxVr6xHg83w+12y4YDq2NlUTfd8oOFQbeV YCxgJmQYtdNaZHCdFrkdsfCcqB5vi/cadAs7Z8WBCPbH4tQBjcmqQqPJW7yN5njo 8rANqLttBBqS9FRl0Txdq/LgcSLlGj/2vndvKwh5plzZMk4SYP7SFht4AZaGFTDF WzBxhy958XPjT2qtm9gUb48QRr/xdV/A5XbUQKAx0qLMsvP+hdOtbhEB6tOIlrbO FFA8MZCzwqRK0Tul7e3eK4b63Xv+MDIEVzxAvLdGbUIJYfqVfPye4bvsHXqY672e CCwwM28STGA9kAu6jQlVw== 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= fm1; t=1710283448; x=1710369848; bh=Y0234bVBwqUQILBnapCT6OCSyEWm NQKMGcosq+eMbhU=; b=V0/dmwjpYiqk3joMu4uc4oykTOVitT8TxKYQ3Jlxl2pe fAHfHft3hicKJYOSxB+3/+e4zdBFODAPMrOCWpjPysLuaX04N5BNWNhOe3L+7W+5 RvaP3P+AjRB+oFlYsJBIE6OvqTjA6nFKx2gmMs/3NUOTVOgSWu4Sucu6PFAQUNTm VnI6S+HHF1p9vSPR4SqlNT0h6WhkQVp7gK06ertqEgz3Nw4oiaHSSKkH8bT6wuOi TPicMeNMMtNUFSkMZ2zLfD4auD6PFzXeet4XNfeR3o4mN+tELUpYSDCO1lMvXDj7 3YYlEmiq44enEMDMqU31asdbl36Oc7YB+nPS/Ze9LQ== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvledrjeeggddtudcutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenog fuuhhsphgvtghtffhomhgrihhnucdlgeelmdenucfjughrpefofgggkfgjfhffhffvufgt sehttdertderredtnecuhfhrohhmpedfnfgrrhhrhicuifgrrhhfihgvlhgufdcuoehlrg hrrhihsehgrghrfhhivghlughtvggthhdrtghomheqnecuggftrfgrthhtvghrnhepfeel ueeltdfggeevheekgffhhedtkeetteeggeefudekvefhueeikeelhfdtheeunecuffhomh grihhnpeefvheglhdrohhrghenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhep mhgrihhlfhhrohhmpehlrghrrhihsehgrghrfhhivghlughtvggthhdrtghomh X-ME-Proxy: Feedback-ID: i8414410d:Fastmail Received: by mailuser.nyi.internal (Postfix, from userid 501) id 727771700093; Tue, 12 Mar 2024 18:44:08 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface User-Agent: Cyrus-JMAP/3.11.0-alpha0-251-g8332da0bf6-fm-20240305.001-g8332da0b Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net MIME-Version: 1.0 Message-ID: <7eada0fd-39c5-4a89-8c74-80c671801a2d@app.fastmail.com> In-Reply-To: References: Date: Tue, 12 Mar 2024 22:43:46 +0000 To: "php internals" Subject: Re: [PHP-DEV] [RFC[ Property accessor hooks, take 2 Content-Type: text/plain From: larry@garfieldtech.com ("Larry Garfield") On Tue, Mar 12, 2024, at 10:09 PM, Rowan Tommins [IMSoP] wrote: >> if a `get` hook for property `$foo` calls method `bar()`, then inside that method `$this->foo` will refer to the raw property, both read and write. If `bar()` is called from somewhere other than the hook, reading from `$this->foo` will trigger the `get` hook. This behavior is identical to that already used by `__get` and `__set` today. > > > > I'm slightly confused by this. > > If there is an actual property called $foo, then __get and __set will > be called only when it is out of visibility, regardless of the call > stack - e.g. a private property will always trigger __get from public > scope, and always access it directly from private scope: > https://3v4l.org/R5Yos That seems differ from what's proposed, where > even a private call to bar() would trigger the hook. > > The protection against recursion appears to only be relevant for > completely undefined properties. For __get, the direct access can never > do anything useful - there's nothing to access: https://3v4l.org/2nDZS > For __set, it is at least possible for the non-recursive write to > succeed, but only in the niche case of creating a dynamic property: > https://3v4l.org/dpYOj I'm not sure that there's any equivalent to this > scenario for property hooks, since they can never be undefined/dynamic. It's slightly different, yes. The point is that the special behavior of a hook is disabled if you are within the call stack of a hook, just like the special behavior of __get/__set is disabled if you are within the call stack of __get/__set. What happens when you hit an operation that would otherwise go into an infinite loop is a bit different, but the "disable to avoid an infinite loop" logic is the same. So maybe "is the same" rather than "is identical", but otherwise it's the same concept. >> There is one exception to the above: if a property is virtual, then there is no presumed connection between the get and set operations. [...] For that reason, `&get` by reference is allowed for virtual properties, regardless of whether or not there is a `set` hook. > > > I don't agree with this, and the example immediately following it > demonstrates the exact opposite: the &get and set hooks are both > proxying to the same backing value, and have all the same problems as > if the property was non-virtual. I would imagine a lot of real-life > virtual properties would be doing something similar: converting to/from > a different type, proxying to another object, etc. > > I think this exception is unnecessarily complicated: either trust users > to handle the implications of combining &get with set, or forbid it. The point is to give the user the option for full backwards compatibility when it makes sense. This requires jumping through some hoops, which is the point. This is essentially equivalent to creating a by-ref getter + a setter, exposing the underlying property. By creating a virtual property, we are "accepting" that the two are detached. While we could disallow this, we recognize that there may be valid use-cases that we'd like to enable. It also parallels __get/__set, where using &__get means you can write to something without going through __set. In practice I expect it virtual properties with both hooks to be very rare. Most virtual properties will, I expect, be lazy-computed get-only values. >> Additionally, `&get` hooks are allowed for arrays as well, provided there is no `set` hook. > > > I mentioned in a previous e-mail the possibility of using the &get hook > for array writes. Has this been considered? > > That is: > > $c->arr['beep'] = 'boop'; > > Would be equivalent to: > > $temp =& $c->arr; > $temp['beep'] = 'boop'; > unset($temp); > > Which would be valid if $arr had an &get hook defined. With the change to allow &get in the absence of set, I believe that would already work. cf: https://3v4l.org/3Gnti/rfc#vrfc.property-hooks >> A `set` hook on a typed property must declare a parameter type that is the same as or contravariant (wider) from the type of the property. > >> Once a property has both a `get` and `set` operation, however, it is no longer covariant or contravariant for further extension. > > > > How do these two rules interact? > > Could this: > > public string $foo { > get => $this->_foo; > set(string|Stringable $value) { > $this->_foo = (string)$value; > } > } > > be over-ridden by this, where the property's "main type" remains > invariant but its "settable type" is contravariant? > > public string $foo { > get => $this->_foo; > set(string|Stringable|SomethingElse $value) { > $this->_foo = $value instanceof SomethingElse ? > $value->asString() : (string)$value; > } > } That would be legal. >> ReflectionProperty has several new methods to work with hooks. > > > There should be some way to reliably determine the "settable type" of a > property. At the moment, I think you would have to do something like > this: > > $setHook = $property->getHook(PropertyHookType::Set); > $writeType = $setHook === null ? $property->getType() : > $setHook->getParameters()[0]->getType(); Hm. Good point here. We'll probably need to add another method to ReflectionProperty for that. Stay tuned. --Larry Garfield