Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:123084 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 0DC1A1A009C for ; Wed, 10 Apr 2024 08:29:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1712737812; bh=5qGKZak2PZH80ax3FueZg27xP5yMsq5JHZiGh4VzKkQ=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=J4pL77AcEGCnZ06CiMLrD5/zI+zbORwdPyJkxVEQC9R3fIjuny5P9+5AK8/Sp3QGy 9XxaIrle2gy609qivEOW8u0WJFvjn0xNCo0VCU7lKqs+lGnflXaEkQesiyUEoRV7Zd 3I6odhMKPcRy90rQ8Pc3b98TPK6/DEPuv/tmcDwPOlKl9M6onsUjaeA60VLqHY9mqV nbwlr+6CSgPdRHzULb5CfUJOccWuSPNKG8tzVOQU4If+uOBNLi7glsieuxyEbr0AKO DpuI8naEOyNsUNwHFkMhMzYYRdlpKmBDx1QgJ8jJqRunpxctg2r3SG03b1O9GXIXbR S6Hw6Mmff9e6g== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id DB6A91806D7 for ; Wed, 10 Apr 2024 08:30:05 +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.7 required=5.0 tests=BAYES_05,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, HTML_MESSAGE,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE, SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from mail-lf1-f47.google.com (mail-lf1-f47.google.com [209.85.167.47]) (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 ; Wed, 10 Apr 2024 08:30:01 +0000 (UTC) Received: by mail-lf1-f47.google.com with SMTP id 2adb3069b0e04-516d2600569so7027292e87.0 for ; Wed, 10 Apr 2024 01:29:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1712737767; x=1713342567; darn=lists.php.net; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=iZOsx5G/X9GnWcfsHeV3miLZSqQ7sAXqSWOcy3rAjbQ=; b=chv5Ic/sxVbgIX0KMPnP+mHOL7cgKSiUMh8131fpzVumfj9Ga4B2xy7qmZQ+YTfuKE glpS3y47wH7Y6iFgUTa4sIkoPH2fnzd1s4KNQBly4lgBH1+f2Sf2EkRTiiaM1EBFNY1M 4J0MoE0FUnt21H4VVYWVg7S/OKuUtAizvbA643mWo7ykE6eBjKKyWFrBjFzEKSb5t264 TNX+N1DpjIfRkMPF4GLm8rOxfZLcQ/OusnXPrzRKgGi5x4S5RiLwNvFZpiX+v300ioNh Y9IWp1azkantOFbFEb6lpFg6s7AP6JUkAFoehB3v8Mg2oCQZT6VypaUFL8ZudFaxUAfR I00A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1712737767; x=1713342567; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=iZOsx5G/X9GnWcfsHeV3miLZSqQ7sAXqSWOcy3rAjbQ=; b=ADUgPR8knv1kov8qtb1AiwV5AOu4iXDJcdXUtxoa2uQiJ1Z0qLO+j2TyTouH9qOLGd +UWfk14S0Jlzmh+2wUxsPSRr/vNnH3Fsb178T6a1VSs3SFvM9V59IUE0ErDk9AR4A9rp ujv6gTsu0WGwYnvzW8Vp0F7oYPw0SKbPeq8Wx3IG/IJxgzHWCLMA1sNuMUX4J3PMuXYD So2IMuw2iT78w22bKwTK4wzlSl3HdJBx9VzJXutxdcTZRMdUfyzL6b0HnivRdo9Q8daK X0Wsu4bLxt97efZxdrZr+sTA523Wt+T1tyT1oxabsyBhkQKkMDSlkx4c21P9YA3nawDo kDlQ== X-Gm-Message-State: AOJu0YzAs6Bx3wgywf+0nFZMVCdxyu80oJZe6fDnkL3YhkbhNGhaitzQ 4zuJgi8SFYnYSbA1ZrDLDHt1Wf6a1n3i30S++7TzAGr4ETU041unarLySDTuZGWAm1lcp3KVVU0 358n8Ota8SQ2+4jNhx5yM8NaH4xB24ZTdgEE= X-Google-Smtp-Source: AGHT+IFf4cQBrLEZc6Jr2+pScmpKcgg3+2yhFDT2vgEnK+qI2PMgF6pLjUbE6opwnkSnSppTdRLDojkw/s6qIksAOF0= X-Received: by 2002:ac2:5b81:0:b0:515:aae5:6c11 with SMTP id o1-20020ac25b81000000b00515aae56c11mr1173372lfn.34.1712737766820; Wed, 10 Apr 2024 01:29:26 -0700 (PDT) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net MIME-Version: 1.0 References: <66154AA0.1040905@adviesenzo.nl> <66160A1D.4060409@adviesenzo.nl> In-Reply-To: <66160A1D.4060409@adviesenzo.nl> Date: Wed, 10 Apr 2024 11:28:50 +0300 Message-ID: Subject: Re: [PHP-DEV] [RFC][Vote announcement] Property hooks To: Juliette Reinders Folmer Cc: internals@lists.php.net Content-Type: multipart/alternative; boundary="0000000000002f52620615b9d6ae" From: arvids.godjuks@gmail.com (Arvids Godjuks) --0000000000002f52620615b9d6ae Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Wed, 10 Apr 2024 at 06:43, Juliette Reinders Folmer < php-internals_nospam@adviesenzo.nl> wrote: > On 9-4-2024 16:03, Juliette Reinders Folmer wrote: > > On 8-4-2024 23:39, Ilija Tovilo wrote: > > Hi everyone > > Heads-up: Larry and I would like to start the vote of the property > hooks RFC tomorrow:https://wiki.php.net/rfc/property-hooks > > We have worked long and hard on this RFC, and hope that we have found > some middle-ground that works for the majority. One last concern we > have not officially clarified on the list: > https://externals.io/message/122445#122667 > > I personally do not feel strongly about whether asymmetric types make it = into the initial implementation. Larry does, however, and I think it is not= fair to exclude them without providing any concrete reasons not to. [snip] > > My concern is more about the external impact of what is effectively a cha= nge to the type system of the language: [snip] will tools like PhpStan and = Psalm require complex changes to analyse code using such properties? > > In particular, this paragraph is referencing the ability to widen the > accepted $value parameter type of the set hook, described at the > bottom of https://wiki.php.net/rfc/property-hooks#set. I have talked > to Ond=C5=99ej Mirtes, the maintainer of PHPStan, and he confirmed that > this should not be complex to implement in PHPStan. In fact, PHPStan > already offers the @property-read and @property-write class > annotations, which can be used to describe "virtual" properties > handled within __get/__set, already providing asymmetric types of > sorts. Hence, this concern should be a non-issue. > > Thank you to everybody who has contributed to the discussion! > > Ilija > > > > Ilija, > > Heads-up: I'm still writing up an opinion and intend to send it to the > list before end of day (CET). I know I'm late to the party, but I've been > having trouble finding the words to express myself properly regarding thi= s > RFC (and have been struggling to find the right words for months). > > Smile, > Juliette > > > Later than intended, but here goes.... > > If there is one RFC which has been giving me nightmares since I first > heard of it, it's this one. > > I realize it is late in the discussion period to speak up, but for months > I've been trying to find the words to express my concerns in a polite and > constructive way and have failed. > > I am going to try now anyway (before it is too late), so please bear with > me. Also, as I'm not a C-developer, please forgive me if I get the > internals wrong. I'm writing this from a PHP-dev/user perspective, with m= y > perspective being heavily influenced by my role as maintainer of > PHP_CodeSniffer. > > --- > TL;DR: this RFC tries to do too much in one go and introduces a huge > amount of cognitive complexity with all the exceptions and the difference= s > in behaviour between virtual and backed properties. This cognitive > complexity is so high that I expect that the feature will catch most > developers out a lot of the time. > --- > > I can definitely see the use case and desirability of the property hooks > functionality proposed in the RFC and compared to the initial RFC I read > last year, the current RFC is, IMO, much improved. > Huge kudos to Ilija and Larry for all the work they have put in to this! > > I applaud the intention of this RFC to make it easier to avoid the magic > __get()/__set() et al methods. What I have a problem with is the > implementation details. > > Over the last few years, we've seen a movement to get rid of more and mor= e > of the _surprising_ behaviour of PHP, with subtle exceptions being > deprecated and slated for removal and (most) new syntaxes trying to use t= he > principle of least surprise by design. > > This RFC, in my view, is in stark contrast to this as it introduces a > plethora of exceptions and subtle different behaviour in a way that will > catch developers out for years to come. > > At this moment (excluding property hooks), from a user perspective, there > are three different function syntaxes in PHP: named functions (and > methods), anonymous functions and arrow functions. > > The semantics of these are very similar with subtle differences: > * Can be static or non-static. > * Take parameters, which can be typed, references, variadic, optional etc= . > * Can have a return type. > * Can return by reference. > * Have a function "body". > > The differences between the current syntaxes - from a user perspective - > are as follows: > =3D Named functions: > * When declared in a class, can have visibility attached, can be abstract= , > can be final. > * When declared in an interface or declared as abstract, will not have a > function "body". > > =3D Anonymous functions: > * Can import plain variables from outside its scope with a `use()` clause= . > * Are declared as an expression (can be assigned to a variable etc). > > =3D Arrow functions: > * Have access to variables in the same scope. > * Are declared as an expression. > * Body of the function starts with a =3D> instead of being enclosed in > curlies and can end on a range of characters. > * Can only take one statement in the body. > * Automagically returns. > > The property hooks RFC introduces a fourth flavour of function syntax. An= d > not just one syntax, but five and the differences in the semantics of the > function syntaxes are significant. > > The differences in semantics I see for "full" property hook functions > compared to other function syntaxes are as follows: > * `get` cannot take parameters (and doesn't have the parentheses typicall= y > expected for a function declaration). > * `get` cannot take return type (inherits this from the property, which i= s > logically sound, but does create a syntactic difference). > * `set` can take one (typed or untyped) parameter. > * `set` cannot take return type (silently set to void, which is logically > sound, but does create a syntactic difference). > * `set` magically creates a $value variable for the "new" value, though > that variable _may_ have an arbitrary different name depending on whether > or not the parameter was explicitly specified. > * Has a function body. > > Then there are multiple short hand syntaxes, which each have yet more > syntactic differences: > * The arrow function variant for `get` with all the above differences + > the differences inherent to arrow functions, combined, with the exception > of the access to variables in the same scope and a more clearly defined e= nd > of the expression. > * The implicit "set" parameter, which does not have a explicit parameter, > does not have parentheses and has the magically created $value variable. > * The arrow function variant for `set` with all the above differences + > the differences inherent to arrow functions with the above mentioned > exceptions + the implicit assignment, which breaks the expected behaviour > of arrow functions by assigning the result of the expression instead of > returning it (totally understandable, but still a difference). > * The abstract/interface variants, which don't have a function body. > > Next there are the differences in semantics which are now being introduce= d > for properties: > * Aside from the hooks themselves.... > * Properties _may_ or _may not_ have a default value anymore, depending o= n > whether the hooks cause it to be a backed or a virtual property. > * Properties with hooks can _be_ readonly, but cannot be declared as > readonly. > > And then there are the new features for properties (not just hooked ones)= : > * Properties can now be declared as final. > * Properties can now be declared as abstract, but only with explicit hook > requirements, otherwise the abstract keyword is not allowed. > * Properties can now be declared on interfaces, but only with explicit > hook requirements, otherwise they are not allowed. > * Abstract/Interface properties don't comply with the same > covariance/contravariance rules as other properties > > And last but not least, there is the ability to declare property hooks in > constructor property promotion ... where we can now basically have a > function declaration within the signature of a method declaration.... wit= h > all five possible syntax types. > > Additionally, when reading the RFC (in its current state), I see the > following exceptions being put in place, which impact the semantics for > properties: > * Only available for object properties, static properties are excluded. > * `var` for property declarations is not supported according to the RFC. > While I 100% agree using the var keyword is old-school, using `var` > effectively makes a property a public property (which would satisfy the > visibility requirement for an interface/abstract class) and the `var` > keyword is *not* deprecated, even though the RFC states it is: > https://3v4l.org/3o50a > I'd fully support formally deprecating the `var` keyword for propertie= s > and eventually removing it, but not supporting it for this RFC, even thou= gh > it is still a supported language feature seems opinionated and arbitrary. > Note: when testing the RFC code, declaring a property using the var > keyword on an interface does not currently throw an error (while if it is > not supported, I would expect one): > > https://3v4l.org/KaLqe/rfc#vrfc.property-hooks , same goes for using the > var keyword with property hooks in a class: > https://3v4l.org/mQ6pG/rfc#vrfc.property-hooks > * Disallows references to properties, but only when there is a set hook. > * Disallows indirect modification of a property, but only when there is a > set hook. > * Write-only (virtual) properties, which cannot be read and you need to > study the hook declaration in detail to figure out if a property is or is > not write-only. > Oh, and hang on, they *can* be read from a method in the same class as > long as that method is called from within the set hook, so now the method > will need to either do a backtrace or use Reflection to figure out whethe= r > it has access to the property value (now why does that remind me of the > magic __...() methods ?). > * Readonly properties which are not denoted as readonly, but still are du= e > to their virtual nature (get without access to $this->prop), which can on= ly > be figured out by, again, studying the contents of the hook function. > * Whether a type can be specified on the parameter on `set` depends on > whether the property is typed. You cannot declare `set(mixed $value)` for > an untyped property, even though it would effectively be compatible. This > is inconsistent with the behaviour for, for instance method overloads, > where this is acceptable: > https://3v4l.org/hbCor/rfc#vrfc.property-hooks , though it is consistent > with the behaviour of property overloads, where this is not acceptable: > https://3v4l.org/seDWM (anyone up for an RFC to fix this inconsistency ?) > * Changes the meaning of `$this->property` read/write access for all > methods called from within a hook while executing the hook. > * Creates two different flavour of properties: "backed" properties and > "virtual" properties with significantly different behaviours, raising > cognitive complexity. > This includes, but is not limited to the fact that set hooks can be > bypassed on virtual properties via a get reference. > * The range of different behaviours for various forms of serialization. > > Furthermore: > > [1] The RFC also states in "Interaction with isset() and unset()" that th= e > behaviour of property hooks is consistent with how `isset()` interacts wi= th > `__get()` today. This is not true, as in: the behaviour as described for > isset with magic methods is different than what the RFC states it is: > https://3v4l.org/2Arkh/rfc#vrfc.property-hooks > > Additionally, it proposes for isset() to throw an Error for virtual > properties without a get hook. This is surprising behaviour as isset() by > its nature is expected to *not* throw errors, but return false for whatev= er > is not set or inaccessible from the current context: > https://3v4l.org/3OlgM > > [2] PHP supports "multi-property declarations", but I see no mention of > these in the RFC, which makes it unclear if and if so, how property hooks > would work with multi-property declarations. > class Foo { > public string $bar, $baz, $bab; > } > > [3] If a `set` hook gets a named parameter, is the magic `$value` variabl= e > still available or not ? I'd expect not, but it is unclear from the RFC. > > [4] Why should ReflectionProperty::getRawValue() throw an error for stati= c > properties ? Instead of returning the value, identically to > ReflectionProperty::getValue() ? This is surprising to me and I see no > reason for it. > > > All in all, I really do see the use case for this feature and I most > definitely appreciate all the work Ilija and Larry have put into the RFC > and the implementation. > > However, in its current state, I'm concerned that the feature introduces > so many exceptional situations and WTF moments that it is a worse solutio= n > than the magic methods which are already available. (and no, I'm definite= ly > not a fan of those magic methods either). > > I think property hooks as currently proposed with all its catches will be > hard to teach, will raise the barrier of entry to the language, can catch > people out in dozens of different ways and introduces way too many > peculiarities, while the tendency of the language has been to try to > eliminate those kind of surprising behaviours. > > Irrelevant side-note: I kind of feel like I could create a completely new > "Why Equal doesn't Equal" Quiz just and only based on property hooks and > people will still not get it afterwards. > > --- > > As for the impact on static analysis tools.... > > I can't speak for other tools, but I can tell you that for PHP_CodeSniffe= r > the impact of this RFC will be horrendous. Aside from the impact on the > syntax recognition layer (Tokenizer), my rough estimate is that about 70% > of all sniffs ever written will need to be adjusted for these five syntax= es > and all the peculiarities around them - either to ignore hooks, work arou= nd > hooks, skip over hooks, or to take hooks into account and examine them in > all their variations. > I estimate it will take a good 5-6 years before all actively used sniffs > will have been adjusted and that in the mean time, maintainers of both > PHPCS itself as well as the popular external standards will have to deal > with a significant number of extra support requests/bug reports related t= o > this. > > The sheer amount of new syntaxes which have been introduced starting with > PHP 7.4, has already brought innovation in a large part of the > PHP_CodeSniffer field to a near complete halt for the past four years as > I'm continuously trying to play catch-up. This RFC will mean that > innovation, like new PSR-5/19 Docs standards, QA sniffs for tests, > significantly improving the Security standard etc, will all be put on hol= d > for another few years while I have to deal with this change. > > While I fully recognize that the impact on userland tooling is not a > reason to reject a new PHP feature, nor should it be, I do believe that t= he > impact of this RFC could be far less and easier to mitigate if different > design choices were made or if the new syntaxes were introduced in a far > slower, more staged approach across multiple PHP versions. > > Smile, > Juliette > > P.S.: nitpick: in the first two code examples under "Detailed > Implementation" - "Set" the `$u` variable is missing the dollar sign for > the `new User` line. > So seeing how big this feedback was, I gave the RFC a proper read before I read this feedback message and frankly, as a userland developer, I checked out at the "Here is a exhaustive list of possible hook combinations and their supported operations." and just stopped reading because at that point my brain seized up and I understand nothing. What's more damming - I do not want to understand it and I'm looking at it as "I'm gonna have a .git hook that prohibits hooks period - it's so complicated and convoluted that I do not trust with it myself and not even talking about less experienced developers in my teams". The amount of complexity in these two hooks is on the level of the whole PHP OOP model with the number of footguns and WTF cases to rival magic quotes, register_globals=3Don and every other infamous gotcha we had in the engine that got deleted out of existence. And then there's the whole "chained methods" part that's missing at all. If I want chained methods, that means the setter hooks are useless for me, meaning we are back to just using get*() and set*() methods anyway, making the hooks kind'a irrelevant. --=20 Arv=C4=ABds Godjuks +371 26 851 664 arvids.godjuks@gmail.com Telegram: @psihius https://t.me/psihius --0000000000002f52620615b9d6ae Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable


=
On Wed, 10 Apr 2024 at 06:43, Juliett= e Reinders Folmer <php-internals_nospam@adviesenzo.nl> wrote:
=20 =20 =20
On 9-4-2024 16:03, Juliette Reinders Folmer wrote:
=20
On 8-4-2024 23:39, Ilija Tovilo wrote:
Hi everyone

Heads-up: Larry and I would like to start the vote of the property
hooks RFC tomorrow:
https=
://wiki.php.net/rfc/property-hooks

We have worked long and hard on this RFC, and hope that we have found
some middle-ground that works for the majority. One last concern we
have not officially clarified on the list:

ht=
tps://externals.io/message/122445#122667

I personally do not feel strongly about whether asymmetric=
 types make it into the initial implementation. Larry does, however, and I =
think it is not fair to exclude them without providing any concrete reasons=
 not to. [snip]
My concern is more about the external impact of what is effe=
ctively a change to the type system of the language: [snip] will tools like=
 PhpStan and Psalm require complex changes to analyse code using such prope=
rties?
In particular, this paragraph is referencing the ability to wi=
den the
accepted $value parameter type of the set hook, described at the
bottom of https://wiki.php.net/rfc/property-hooks#set. I have talked
to Ond=C5=99ej Mirtes, the maintainer of PHPStan, and he confirmed that
this should not be complex to implement in PHPStan. In fact, PHPStan
already offers the @property-read and @property-write class
annotations, which can be used to describe "virtual" properties
handled within __get/__set, already providing asymmetric types of
sorts. Hence, this concern should be a non-issue.

Thank you to everybody who has contributed to the discussion!

Ilija


Ilija,

Heads-up: I'm still writing up an opinion and intend to send it t= o the list before end of day (CET). I know I'm late to the party, but I've been having trouble finding the words to express myself properly regarding this RFC (and have been struggling to find the right words for months).

Smile,
Juliette

Later than intended, but here goes....

If there is one RFC which has been giving me nightmares since I first heard of it, it's this one.

I realize it is late in the discussion period to speak up, but for months I've been trying to find the words to express my concerns in a polite and constructive way and have failed.

I am going to try now anyway (before it is too late), so please bear with me. Also, as I'm not a C-developer, please forgive me if I get the internals wrong. I'm writing this from a PHP-dev/user perspective, with my perspective being heavily influenced by my role as maintainer of PHP_CodeSniffer.

---
TL;DR: this RFC tries to do too much in one go and introduces a huge amount of cognitive complexity with all the exceptions and the differences in behaviour between virtual and backed properties. This cognitive complexity is so high that I expect that the feature will catch most developers out a lot of the time.
---

I can definitely see the use case and desirability of the property hooks functionality proposed in the RFC and compared to the initial RFC I read last year, the current RFC is, IMO, much improved.
Huge kudos to Ilija and Larry for all the work they have put in to this!

I applaud the intention of this RFC to make it easier to avoid the magic __get()/__set() et al methods. What I have a problem with is the implementation details.

Over the last few years, we've seen a movement to get rid of more and more of the _surprising_ behaviour of PHP, with subtle exceptions being deprecated and slated for removal and (most) new syntaxes trying to use the principle of least surprise by design.

This RFC, in my view, is in stark contrast to this as it introduces a plethora of exceptions and subtle different behaviour in a way that will catch developers out for years to come.

At this moment (excluding property hooks), from a user perspective, there are three different function syntaxes in PHP: named functions (and methods), anonymous functions and arrow functions.

The semantics of these are very similar with subtle differences:
* Can be static or non-static.
* Take parameters, which can be typed, references, variadic, optional etc.
* Can have a return type.
* Can return by reference.
* Have a function "body".

The differences between the current syntaxes - from a user perspective - are as follows:
=3D Named functions:
* When declared in a class, can have visibility attached, can be abstract, can be final.
* When declared in an interface or declared as abstract, will not have a function "body".

=3D Anonymous functions:
* Can import plain variables from outside its scope with a `use()` clause.
* Are declared as an expression (can be assigned to a variable etc).
=3D Arrow functions:
* Have access to variables in the same scope.
* Are declared as an expression.
* Body of the function starts with a =3D> instead of being enclosed in curlies and can end on a range of characters.
* Can only take one statement in the body.
* Automagically returns.

The property hooks RFC introduces a fourth flavour of function syntax. And not just one syntax, but five and the differences in the semantics of the function syntaxes are significant.

The differences in semantics I see for "full" property hook functions compared to other function syntaxes are as follows:
* `get` cannot take parameters (and doesn't have the parentheses typically expected for a function declaration).
* `get` cannot take return type (inherits this from the property, which is logically sound, but does create a syntactic difference).
* `set` can take one (typed or untyped) parameter.
* `set` cannot take return type (silently set to void, which is logically sound, but does create a syntactic difference).
* `set` magically creates a $value variable for the "new" val= ue, though that variable _may_ have an arbitrary different name depending on whether or not the parameter was explicitly specified.
* Has a function body.

Then there are multiple short hand syntaxes, which each have yet more syntactic differences:
* The arrow function variant for `get` with all the above differences + the differences inherent to arrow functions, combined, with the exception of the access to variables in the same scope and a more clearly defined end of the expression.
* The implicit "set" parameter, which does not have a explici= t parameter, does not have parentheses and has the magically created $value variable.
* The arrow function variant for `set` with all the above differences + the differences inherent to arrow functions with the above mentioned exceptions + the implicit assignment, which breaks the expected behaviour of arrow functions by assigning the result of the expression instead of returning it (totally understandable, but still a difference).
* The abstract/interface variants, which don't have a function body= .

Next there are the differences in semantics which are now being introduced for properties:
* Aside from the hooks themselves....
* Properties _may_ or _may not_ have a default value anymore, depending on whether the hooks cause it to be a backed or a virtual property.
* Properties with hooks can _be_ readonly, but cannot be declared as readonly.

And then there are the new features for properties (not just hooked ones):
* Properties can now be declared as final.
* Properties can now be declared as abstract, but only with explicit hook requirements, otherwise the abstract keyword is not allowed.
* Properties can now be declared on interfaces, but only with explicit hook requirements, otherwise they are not allowed.
* Abstract/Interface properties don't comply with the same covariance/contravariance rules as other properties

And last but not least, there is the ability to declare property hooks in constructor property promotion ... where we can now basically have a function declaration within the signature of a method declaration.... with all five possible syntax types.

Additionally, when reading the RFC (in its current state), I see the following exceptions being put in place, which impact the semantics for properties:
* Only available for object properties, static properties are excluded.
* `var` for property declarations is not supported according to the RFC. While I 100% agree using the var keyword is old-school, using `var` effectively makes a property a public property (which would satisfy the visibility requirement for an interface/abstract class) and the `var` keyword is *not* deprecated, even though the RFC states it is: http= s://3v4l.org/3o50a
=C2=A0=C2=A0 I'd fully support formally deprecating the `var` keywo= rd for properties and eventually removing it, but not supporting it for this RFC, even though it is still a supported language feature seems opinionated and arbitrary.
=C2=A0=C2=A0 Note: when testing the RFC code, declaring a property usin= g the var keyword on an interface does not currently throw an error (while if it is not supported, I would expect one): https://3v4l.org/K= aLqe/rfc#vrfc.property-hooks , same goes for using the var keyword with property hooks in a class: https://3v4l.org/mQ6pG/rfc#vrfc.property-hooks
* Disallows references to properties, but only when there is a set hook.
* Disallows indirect modification of a property, but only when there is a set hook.
* Write-only (virtual) properties, which cannot be read and you need to study the hook declaration in detail to figure out if a property is or is not write-only.
=C2=A0=C2=A0 Oh, and hang on, they *can* be read from a method in the s= ame class as long as that method is called from within the set hook, so now the method will need to either do a backtrace or use Reflection to figure out whether it has access to the property value (now why does that remind me of the magic __...() methods ?).
* Readonly properties which are not denoted as readonly, but still are due to their virtual nature (get without access to $this->prop), which can only be figured out by, again, studying the contents of the hook function.
* Whether a type can be specified on the parameter on `set` depends on whether the property is typed. You cannot declare `set(mixed $value)` for an untyped property, even though it would effectively be compatible. This is inconsistent with the behaviour for, for instance method overloads, where this is acceptable: https://3v= 4l.org/hbCor/rfc#vrfc.property-hooks , though it is consistent with the behaviour of property overloads, where this is not acceptable: https://3v4l.org/seDWM (anyone up for an RFC to fix this inconsistency ?)
* Changes the meaning of `$this->property` read/write access for all methods called from within a hook while executing the hook.
* Creates two different flavour of properties: "backed" prope= rties and "virtual" properties with significantly different behavio= urs, raising cognitive complexity.
=C2=A0=C2=A0=C2=A0 This includes, but is not limited to the fact that s= et hooks can be bypassed on virtual properties via a get reference.
* The range of different behaviours for various forms of serialization.

Furthermore:

[1] The RFC also states in "Interaction with isset() and unset()&q= uot; that the behaviour of property hooks is consistent with how `isset()` interacts with `__get()` today. This is not true, as in: the behaviour as described for isset with magic methods is different than what the RFC states it is: https://3v4l.org/2Arkh/rfc#vrfc.prope= rty-hooks

Additionally, it proposes for isset() to throw an Error for virtual properties without a get hook. This is surprising behaviour as isset() by its nature is expected to *not* throw errors, but return false for whatever is not set or inaccessible from the current context: https://3= v4l.org/3OlgM

[2] PHP supports "multi-property declarations", but I see no = mention of these in the RFC, which makes it unclear if and if so, how property hooks would work with multi-property declarations.
class Foo {
=C2=A0=C2=A0=C2=A0 public string $bar, $baz, $bab;
}

[3] If a `set` hook gets a named parameter, is the magic `$value` variable still available or not ? I'd expect not, but it is unclear from the RFC.

[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.


All in all, I really do see the use case for this feature and I most definitely appreciate all the work Ilija and Larry have put into the RFC and the implementation.

However, in its current state, I'm concerned that the feature introduces so many exceptional situations and WTF moments that it is a worse solution than the magic methods which are already available. (and no, I'm definitely not a fan of those magic methods either).
I think property hooks as currently proposed with all its catches will be hard to teach, will raise the barrier of entry to the language, can catch people out in dozens of different ways and introduces way too many peculiarities, while the tendency of the language has been to try to eliminate those kind of surprising behaviours.

Irrelevant side-note: I kind of feel like I could create a completely new "Why Equal doesn't Equal" Quiz just and on= ly based on property hooks and people will still not get it afterwards.

---

As for the impact on static analysis tools....

I can't speak for other tools, but I can tell you that for PHP_CodeSniffer the impact of this RFC will be horrendous. Aside from the impact on the syntax recognition layer (Tokenizer), my rough estimate is that about 70% of all sniffs ever written will need to be adjusted for these five syntaxes and all the peculiarities around them - either to ignore hooks, work around hooks, skip over hooks, or to take hooks into account and examine them in all their variations.
I estimate it will take a good 5-6 years before all actively used sniffs will have been adjusted and that in the mean time, maintainers of both PHPCS itself as well as the popular external standards will have to deal with a significant number of extra support requests/bug reports related to this.

The sheer amount of new syntaxes which have been introduced starting with PHP 7.4, has already brought innovation in a large part of the PHP_CodeSniffer field to a near complete halt for the past four years as I'm continuously trying to play catch-up. This RFC will mean that innovation, like new PSR-5/19 Docs standards, QA sniffs for tests, significantly improving the Security standard etc, will all be put on hold for another few years while I have to deal with this change.

While I fully recognize that the impact on userland tooling is not a reason to reject a new PHP feature, nor should it be, I do believe that the impact of this RFC could be far less and easier to mitigate if different design choices were made or if the new syntaxes were introduced in a far slower, more staged approach across multiple PHP versions.

Smile,
Juliette

P.S.: nitpick: in the first two code examples under "Detailed Implementation" - "Set" the `$u` variable is missing the= dollar sign for the `new User` line.

So seeing how big this feedback w= as, I gave the RFC a proper read before I read this feedback message and fr= ankly, as a userland developer, I checked out at the "Here is a exhaus= tive list of possible hook combinations and their supported operations.&quo= t;=C2=A0and just stopped reading because at that point my brain seized up a= nd I understand nothing. What's more damming - I do not want to underst= and it and I'm looking at it as "I'm gonna have a .git hook th= at prohibits hooks period - it's so complicated and convoluted that I d= o not trust with it myself and not even talking about less experienced deve= lopers in my teams".

The amount of complexity= in these two hooks is on the level of the whole PHP OOP model with the num= ber of footguns and WTF cases to rival magic quotes, register_globals=3Don = and every other infamous gotcha we had in the engine that got deleted out o= f existence.

And then there's the whole "= chained methods" part that's missing at all. If I want chained met= hods, that means the setter hooks are useless for me, meaning we are back t= o just using get*() and set*() methods anyway, making the hooks kind'a = irrelevant.
--

Arv= =C4=ABds Godjuks
+371 26 851 664
Te= legram: @psihius=C2=A0ht= tps://t.me/psihius
--0000000000002f52620615b9d6ae--