Hi folks. Ilija is nearly done with the implementation for asymmetric visibility and flushing out edge cases, but we've run into one design question we'd like feedback on.
There's two design decisions we've made at this point, both of which we think are logical and reasonable:
-
If specified, the set visibility must be tighter than the get visibility. So
protected protected(set)
andprotected public(set)
are not permitted, for instance. -
readonly
is a "write once" flag that may be combined with asymmetric visibility. If no set visibility is specified,readoly
impliesprivate(set)
, but a different set visibility may also be provided.
These are both reasonable rules. However, it creates a conflict. Specifically, in the following cases:
public public(set) readonly string $foo
protected protected(set) readonly string $foo
These would be the only way to have a non-private-set readonly property. While the first is in practice quite unlikely, the second has valid use cases. (In particular, a base class that provides properties expected to be set by a child constructor, and then used by a method in the parent class.) However, it would not be allowed under the rules above. Working around it would require specifying public protected(set) readonly...
, which means exposing a property that likely should not be exposed.
That creates an odd situation where readonly and asymmetric visibility may only be combined "sometimes." That is not deesireable. The only way to combine them in their current form is to allow protected protected(set)
only if readonly is in use, which is excessively complicated both to implement and to explain/document/use.
We see two possible ways to resolve this conflict:
-
Relax the set-is-tighter restriction. That would allow
protected protected(set)
etc. on any property. It wouldn't be particularly useful unless readonly is being used, but it would be syntactically legal and behave as you'd expect. We could still disallow "set is more permissive" combinations (eg,private public(set)
), as those have no apparent use case. -
Disallow readonly and asymmetric visibility being combined, because readonly already has a hard-coded implied asymmetric visibility. This option removes some potential use cases (they would most likely drop the readonly), but has the upside that it's easier to re-allow at some point in the future.
-
Some other brilliant idea we've not thought of.
Both are viable approaches with pros and cons. We're split on which way to go with this, so we throw it out to the group for feedback. Which approach would you favor, or do you have some other brilliant idea to square this circle?
--
Larry Garfield
larry@garfieldtech.com
Hi folks. Ilija is nearly done with the implementation for asymmetric
visibility and flushing out edge cases, but we've run into one design
question we'd like feedback on.There's two design decisions we've made at this point, both of which we
think are logical and reasonable:
If specified, the set visibility must be tighter than the get
visibility. Soprotected protected(set)
andprotected public(set)
are not permitted, for instance.
readonly
is a "write once" flag that may be combined with
asymmetric visibility. If no set visibility is specified,readoly
impliesprivate(set)
, but a different set visibility may also be
provided.These are both reasonable rules. However, it creates a conflict.
Specifically, in the following cases:public public(set) readonly string $foo
protected protected(set) readonly string $foo
These would be the only way to have a non-private-set readonly
property. While the first is in practice quite unlikely, the second
has valid use cases. (In particular, a base class that provides
properties expected to be set by a child constructor, and then used by
a method in the parent class.) However, it would not be allowed under
the rules above. Working around it would require specifyingpublic protected(set) readonly...
, which means exposing a property that
likely should not be exposed.That creates an odd situation where readonly and asymmetric visibility
may only be combined "sometimes." That is not deesireable. The only
way to combine them in their current form is to allowprotected protected(set)
only if readonly is in use, which is excessively
complicated both to implement and to explain/document/use.We see two possible ways to resolve this conflict:
Relax the set-is-tighter restriction. That would allow
protected protected(set)
etc. on any property. It wouldn't be particularly
useful unless readonly is being used, but it would be syntactically
legal and behave as you'd expect. We could still disallow "set is more
permissive" combinations (eg,private public(set)
), as those have no
apparent use case.Disallow readonly and asymmetric visibility being combined, because
readonly already has a hard-coded implied asymmetric visibility. This
option removes some potential use cases (they would most likely drop
the readonly), but has the upside that it's easier to re-allow at some
point in the future.Some other brilliant idea we've not thought of.
Both are viable approaches with pros and cons. We're split on which
way to go with this, so we throw it out to the group for feedback.
Which approach would you favor, or do you have some other brilliant
idea to square this circle?
Addendum: Ilija and I were talking past each other a bit, it seems. Allowing protected protected(set) readonly
only in the context of readonly would be straightforward to implement. It's potentially not the easiest to explain that exception, but implementation-wise it's fine.
So that gives another viable option to consider:
- Allow get and set visibility to be both set explicitly to the same level, iff in the presence of readonly. So
protected protected(set) string $foo
is not allowed, butprotected protected(set) readonly string $foo
is allowed. This gives the most options and the least pointless syntax, but at the cost of having an exception that needs to be documented/explained/understood.
--Larry Garfield
readonly
is a "write once" flag that may be combined with asymmetric
visibility. If no set visibility is specified,readoly
implies
private(set)
, but a different set visibility may also be provided.These are both reasonable rules. However, it creates a conflict.
Specifically, in the following cases:public public(set) readonly string $foo
protected protected(set) readonly string $foo
What if the implicit rule for readonly
is changed into protected(set)
?
Let's run with this for a minute.
1- It's not truly a CODE breaking change. Right now if you have a
protected readonly
property, you're either calling the parent constructor
or you're never making use of the variable, otherwise you're getting a
Fatal Error.
2- It's a CONCEPTUAL breaking change. If you've declared a protected readonly
property, you may expect anyone in the inheritance chain to be
calling your constructor. A new PHP version will warn you to either change
your property into protected private(set) readonly
(Rector might be able
to do this) or accept the new behavior.
3- The two logical design choices can be kept.
To be honest, I think asymmetric visibility seems way over complex for very
little benefit, so I'm a bit against the entire feature, but if we were to
have them, it would really be nicer to not have crazy shenanigans involved.
--
Marco Deleu
readonly
is a "write once" flag that may be combined with asymmetric
visibility. If no set visibility is specified,readoly
implies
private(set)
, but a different set visibility may also be provided.These are both reasonable rules. However, it creates a conflict.
Specifically, in the following cases:public public(set) readonly string $foo
protected protected(set) readonly string $foo
What if the implicit rule for
readonly
is changed intoprotected(set)
?
Let's run with this for a minute.1- It's not truly a CODE breaking change. Right now if you have a
protected readonly
property, you're either calling the parent constructor
or you're never making use of the variable, otherwise you're getting a
Fatal Error.
This is untrue. You can declare a private property identically in a parent and child class, even readonly. I'm doing this now in a project. It works, but would be unnecessary if the parent's property were protected(set).
--Larry Garfield
This is untrue. You can declare a private property identically in a
parent and child class, even readonly. I'm doing this now in a project.
It works, but would be unnecessary if the parent's property were
protected(set).--Larry Garfield
I do understand the slight complexity here (perhaps stronger in terms of
implementation), but my assumption was that if a property is private and
"the set visibility must be tighter", PHP would never assume private protected(set) readonly
. In other words, if private readonly
then
private private(set) readonly
, therefore nothing changes. You can keep
the use of disjointed variables in inheritance provided they're all
private. The only concern is when a property is declared protected, which
then evaluates to what I mentioned on the previous email.
I'm also under the stated assumption that public public(set) readonly
is
not something needed to be supported.
--
Marco Deleu
This is untrue. You can declare a private property identically in a
parent and child class, even readonly. I'm doing this now in a project.
It works, but would be unnecessary if the parent's property were
protected(set).--Larry Garfield
I do understand the slight complexity here (perhaps stronger in terms of
implementation), but my assumption was that if a property is private and
"the set visibility must be tighter", PHP would never assumeprivate protected(set) readonly
. In other words, ifprivate readonly
then
private private(set) readonly
, therefore nothing changes. You can keep
the use of disjointed variables in inheritance provided they're all
private. The only concern is when a property is declared protected, which
then evaluates to what I mentioned on the previous email.
I don't follow. Right now, this is legal:
class P {
protected readonly string $foo;
public useFoo() {
if ($this->foo == 'beep') { ... }
}
}
class C extends P {
protected readonly string $foo;
public function __construct(string $foo) {
$this->foo = $foo;
}
}
The redeclaration of $foo is necessary because of the implicit private-set on readonly today. I have code that does this.
If we go with options 1 or 4, then that could be simplified to:
class P {
protected protected(set) readonly string $foo;
public useFoo() {
if ($this->foo == 'beep') { ... }
}
}
class C extends P {
public function __construct(string $foo) {
$this->foo = $foo;
}
}
This would not require "set is wider", just "set is the same".
If we changed readonly to be an implicit protected(set) instead of private(set), that would also resolve that use case but I do not know if that would cause other problems with code like the above.
I'm also under the stated assumption that
public public(set) readonly
is
not something needed to be supported.
I am not aware of any use cases for it, though if it technically becomes possible as a side effect of other changes I don't object.
--Larry Garfield
On Sun, Nov 13, 2022 at 5:09 PM Larry Garfield larry@garfieldtech.com
wrote:
Hi folks. Ilija is nearly done with the implementation for asymmetric
visibility and flushing out edge cases, but we've run into one design
question we'd like feedback on.There's two design decisions we've made at this point, both of which we
think are logical and reasonable:
If specified, the set visibility must be tighter than the get
visibility. Soprotected protected(set)
andprotected public(set)
are
not permitted, for instance.
readonly
is a "write once" flag that may be combined with asymmetric
visibility. If no set visibility is specified,readoly
implies
private(set)
, but a different set visibility may also be provided.
These are both reasonable rules. However, it creates a conflict.
Specifically, in the following cases:
To unsubscribe, visit: https://www.php.net/unsub.php
The more I think about this, the more it makes more sense (to me) to
simplify it even further;
- The set visibility should be the same as the get visibility when one is
not provided. That is:
public $var -> public public(set) $var
protected $var -> protected protected(set) $var
private $var -> private private(set) $var
The explicit declaration of same visibility can be disallowed e.g. public public(set) $var
is not allowed, you must use public $var
if you want
visibility symmetry. However, if it simplifies implementation to allow it,
why not? The behavior would already be in place anyway.
- The readonly flag should no longer have an impact on the set visibility.
This is again a conceptual breaking change, but one that can even be fixed
with a SEARCH/REPLACE on a project scope. The "breaking change" is
categorized as follows:
The code public readonly $var
used to be public private(set) readonly $var
should become public public(set) readonly $var
The code protected readonly $var
used to be protected private(set) readonly $var
should become protected protected(set) readonly $var
The code private readonly $var
should not have any change.
--
Marco Deleu
public public(set) readonly string $foo
protected protected(set) readonly string $foo
These would be the only way to have a non-private-set readonly property. While the first is in practice quite unlikely, the second has valid use cases.
Both have use cases. Whether they are valid is quite subjective. (I am speaking as someone who suffer from the match()
construct forbidding having both default
and some other case
pointing to the same expression. That restriction seemed reasonable the time the feature was designed and voted.)
- Relax the set-is-tighter restriction. That would allow
protected protected(set)
etc. on any property. It wouldn't be particularly useful unless readonly is being used, but it would be syntactically legal and behave as you'd expect. We could still disallow "set is more permissive" combinations (eg,private public(set)
), as those have no apparent use case.
I think that Option 1 is the most reasonable. The meaning of public public(set)
and protected protected(set)
is straightforward; from a user point-of-view, disallowing them seems more like “it is useless” than “it is confusing”. Unless there are good technical reason to restrict it, we can just leave to linting tools the care of reporting it.
—Claude
- Relax the set-is-tighter restriction. That would allow
protected protected(set)
etc. on any property. It wouldn't be particularly useful unless readonly is being used, but it would be syntactically legal and behave as you'd expect. We could still disallow "set is more permissive" combinations (eg,private public(set)
), as those have no apparent use case.I think that Option 1 is the most reasonable. The meaning of
public public(set)
andprotected protected(set)
is straightforward; from a user point-of-view, disallowing them seems more like “it is useless” than “it is confusing”. Unless there are good technical reason to restrict it, we can just leave to linting tools the care of reporting it.—Claude
To clarify my position:
-
The set visibility must be either more restrictive or of the same restriction level than the get visibility.
-
When the set visibility is absent, it is inferred as following:
- If
readonly
is present, the set visibility isprivate
(as of today); - otherwise, the set visibility is the same as the get visibility (again, as of today).
- If
-
We don’t judge whether it is reasonable to write
protected protected(set) string $foo;
when you could just writeprotected string $foo
for the same effect. Similarly, we don’t judge whether it is reasonable to writepublic function()
when you could just writefunction()
for the same effect. We leave it to coding styles and linters to decide whether the short form or the long form is preferred.
—Claude
Hi
To clarify my position:
The set visibility must be either more restrictive or of the same restriction level than the get visibility.
When the set visibility is absent, it is inferred as following:
* Ifreadonly
is present, the set visibility isprivate
(as of today);
* otherwise, the set visibility is the same as the get visibility (again, as of today).We don’t judge whether it is reasonable to write
protected protected(set) string $foo;
when you could just writeprotected string $foo
for the same effect. Similarly, we don’t judge whether it is reasonable to writepublic function()
when you could just writefunction()
for the same effect. We leave it to coding styles and linters to decide whether the short form or the long form is preferred.
I agree with that.
As I'm sending an email anyway: Larry, will there be a a new separate
discussion thread, once all the problems are resolved and once it's
clear what you propose? I just noticed the "Abbreviated Form" section in
the RFC
(https://wiki.php.net/rfc/asymmetric-visibility#abbreviated_form) which
I disagree with, which apparently was added in October, but I remember
an email letting readers know of the updated RFC. I didn't follow the
evolution of the RFC too closely, though, because I believed that it
still was in a somewhat early stage and because discussion is already
split into way-to-many threads and also the poll.
Best regards
Tim Düsterhus
Hi
To clarify my position:
The set visibility must be either more restrictive or of the same restriction level than the get visibility.
When the set visibility is absent, it is inferred as following:
* Ifreadonly
is present, the set visibility isprivate
(as of today);
* otherwise, the set visibility is the same as the get visibility (again, as of today).We don’t judge whether it is reasonable to write
protected protected(set) string $foo;
when you could just writeprotected string $foo
for the same effect. Similarly, we don’t judge whether it is reasonable to writepublic function()
when you could just writefunction()
for the same effect. We leave it to coding styles and linters to decide whether the short form or the long form is preferred.I agree with that.
As I'm sending an email anyway: Larry, will there be a a new separate
discussion thread, once all the problems are resolved and once it's
clear what you propose? I just noticed the "Abbreviated Form" section in
the RFC
(https://wiki.php.net/rfc/asymmetric-visibility#abbreviated_form) which
I disagree with, which apparently was added in October, but I remember
an email letting readers know of the updated RFC. I didn't follow the
evolution of the RFC too closely, though, because I believed that it
still was in a somewhat early stage and because discussion is already
split into way-to-many threads and also the poll.Best regards
Tim Düsterhus
Yes, once we make a decision on this point, I'll respond in this thread.
The abbreviated form was part of the discussion earlier, and the syntax we settled on supported it, so it made sense to include.
I try to highlight on the list any time notable changes are made, even if I don't always have a detailed changelog. Whether it makes sense to use the same thread or a new thread varies, and I'm absolutely certain others will make a different judgement call on that than I do. I'm not aware of any standard convention around that, so until one exists I'll just continue making vaguely educated guesses on that front.
Given the timing, Ilija says he'd prefer to not call the vote until after the new year/holidays. Feedback still welcome at this point but aside from edge cases like this thread's, I think we're pretty well set on the basic features. Baring any major change of direction expect the vote to be called in early January, probably. Time permitting we're going to also start work on property hooks/accessors, which is the intended follow-on to this RFC.
--Larry Garfield
Hi folks. Ilija is nearly done with the implementation for asymmetric visibility and flushing out edge cases, but we've run into one design question we'd like feedback on.
There's two design decisions we've made at this point, both of which we think are logical and reasonable:
If specified, the set visibility must be tighter than the get visibility. So
protected protected(set)
andprotected public(set)
are not permitted, for instance.
readonly
is a "write once" flag that may be combined with asymmetric visibility. If no set visibility is specified,readoly
impliesprivate(set)
, but a different set visibility may also be provided.These are both reasonable rules. However, it creates a conflict. Specifically, in the following cases:
public public(set) readonly string $foo
protected protected(set) readonly string $foo
These would be the only way to have a non-private-set readonly property. While the first is in practice quite unlikely, the second has valid use cases. (In particular, a base class that provides properties expected to be set by a child constructor, and then used by a method in the parent class.) However, it would not be allowed under the rules above. Working around it would require specifying
public protected(set) readonly...
, which means exposing a property that likely should not be exposed.That creates an odd situation where readonly and asymmetric visibility may only be combined "sometimes." That is not deesireable. The only way to combine them in their current form is to allow
protected protected(set)
only if readonly is in use, which is excessively complicated both to implement and to explain/document/use.We see two possible ways to resolve this conflict:
Relax the set-is-tighter restriction. That would allow
protected protected(set)
etc. on any property. It wouldn't be particularly useful unless readonly is being used, but it would be syntactically legal and behave as you'd expect. We could still disallow "set is more permissive" combinations (eg,private public(set)
), as those have no apparent use case.Disallow readonly and asymmetric visibility being combined, because readonly already has a hard-coded implied asymmetric visibility. This option removes some potential use cases (they would most likely drop the readonly), but has the upside that it's easier to re-allow at some point in the future.
Some other brilliant idea we've not thought of.
Both are viable approaches with pros and cons. We're split on which way to go with this, so we throw it out to the group for feedback. Which approach would you favor, or do you have some other brilliant idea to square this circle?
--
Larry Garfield
larry@garfieldtech.com--
To unsubscribe, visit: https://www.php.net/unsub.php
Hi Larry,
I asked for some clarification / further thought about the magic getters/setters interaction of this RFC back when you announced it, and never heard much besides saying that you’re working on a consolidated response to the feedback, but I’ve not seen anything regarding what I’d asked about, and the RFC still seems to have the (IMO) confusing and inconsistent magic getters/setters interaction described.
As I understand it, you’re suggesting that a property declared as public protected(set)
would never trigger __set().
While I understand that this is meant to “keep consistency with readonly”, I would imagine people would want to use native asymmetric visibility on objects that currently have protected (or private) properties that are accessed via magic getters and setters. I think it would be a natural assumption that asymmetric visibility would allow the user to remove the often boilerplate __get method, while maintaining the ability to have checks/other logic beyond simple type checks when a property is being set. Having the association of a set action tied to the get visibility is very unintuitive to me.
The impact of this “same” limitation on readonly properties is IMO greatly reduced, because of the nature of something being readonly. The ability to run some logic when writing to a property that’s otherwise readable is surely a concept that’s very common and easy to understand, it’s literally the next example after (1) “readonly” and (2) “asymmetric visibility” in Nikita’s original property accessors RFC.
The stated reason (on both this and the readonly RFC) for not allowing __set() is "to avoid surprising behaviour”. To me, having a field marked as public protected(set)
then not call __set() when setting a property from outside the class is the surprising behaviour.
Cheers
Stephen
As I understand it, you’re suggesting that a property declared as
public protected(set)
would never trigger __set().
I would think that that would be against our current practice, which is
easy enough to explain as "if the property isn't visible set,
then use __set()". I would argue that "protected(set)" marks a property
as invisible from a non-inherited class/method, and hence __set should
be called.
cheers,
Derick
Hi Derick
As I understand it, you’re suggesting that a property declared as
public protected(set)
would never trigger __set().I would think that that would be against our current practice, which is
easy enough to explain as "if the property isn't visible set,
then use __set()". I would argue that "protected(set)" marks a property
as invisible from a non-inherited class/method, and hence __set should
be called.
What you're describing does not match the readonly behavior.
https://3v4l.org/X76pV
Readonly properties only call __set once they are explicitly unset.
The same applies to __unset. I changed this in the asymmetric
visibility implementation recently to match this behavior but the RFC
has not been adjusted to reflect this yet.
AFAIK this behavior is there to allow calls to __set for certain edge
cases. While not very intuitive it makes sense to stay consistent. If
this behavior is undesirable we should change it in both places.
Ilija
Hi Derick
As I understand it, you’re suggesting that a property declared as
public protected(set)
would never trigger __set().I would think that that would be against our current practice, which is
easy enough to explain as "if the property isn't visible set,
then use __set()". I would argue that "protected(set)" marks a property
as invisible from a non-inherited class/method, and hence __set should
be called.What you're describing does not match the readonly behavior.
https://3v4l.org/X76pVReadonly properties only call __set once they are explicitly unset.
The same applies to __unset. I changed this in the asymmetric
visibility implementation recently to match this behavior but the RFC
has not been adjusted to reflect this yet.AFAIK this behavior is there to allow calls to __set for certain edge
cases. While not very intuitive it makes sense to stay consistent. If
this behavior is undesirable we should change it in both places.
Now I have re-read the Assymetric Visibility RFC's "Interaction with
__set"
(https://wiki.php.net/rfc/asymmetric-visibility#interaction_with_set),
I'm slightly more confused. Could you update that section, as what it
currently states seems reasonable.
cheers,
Derick
There's two design decisions we've made at this point, both of which
we think are logical and reasonable:
If specified, the set visibility must be tighter than the get
visibility. Soprotected protected(set)
andprotected public(set)
are not permitted, for instance.
readonly
is a "write once" flag that may be combined with
asymmetric visibility. If no set visibility is specified,readoly
impliesprivate(set)
, but a different set visibility may also be
provided.These are both reasonable rules. However, it creates a conflict.
Specifically, in the following cases:public public(set) readonly string $foo
protected protected(set) readonly string $foo
Just to see if I understand this correctly, the "protected(set)"
overwrites the implicit "private(set)" that "readonly" confers?
I think that alone is confusing.
These would be the only way to have a non-private-set readonly
property. While the first is in practice quite unlikely, the second
has valid use cases. (In particular, a base class that provides
properties expected to be set by a child constructor, and then used by
a method in the parent class.) However, it would not be allowed under
the rules above. Working around it would require specifyingpublic protected(set) readonly...
, which means exposing a property that
likely should not be exposed.That creates an odd situation where readonly and asymmetric visibility
may only be combined "sometimes." That is not deesireable. The only
way to combine them in their current form is to allowprotected protected(set)
only if readonly is in use, which is excessively
complicated both to implement and to explain/document/use.We see two possible ways to resolve this conflict:
Relax the set-is-tighter restriction. That would allow
protected protected(set)
etc. on any property. It wouldn't be particularly
useful unless readonly is being used, but it would be syntactically
legal and behave as you'd expect. We could still disallow "set is
more permissive" combinations (eg,private public(set)
), as those
have no apparent use case.Disallow readonly and asymmetric visibility being combined, because
readonly already has a hard-coded implied asymmetric visibility.
This option removes some potential use cases (they would most likely
drop the readonly), but has the upside that it's easier to re-allow at
some point in the future.
I am in favour of this option 2. As I already think "protected
protected(set) readonly" is a confusing thing to see. If I hadn't read
this email, I wouldn't have understood the interacting between the
"protected(set)" and "readonly".
cheers,
Derick
Hi Larry,
Regarding the syntax, up until now PHP has only supported the letters
a-z and underscore in keywords.
I realise this is an aesthetic thing, but "private(set)" looks like a
function to me, and not a keyword. I saw the previous poll, and it
didn't include options for either protected_set/private_set or
protectedset/privateset.
Was there a technical reason for excluding them as an option?
That creates an odd situation where readonly and asymmetric visibility
may only be combined "sometimes."...
- Disallow readonly and asymmetric visibility being combined, because
readonly already has a hard-coded implied asymmetric visibility.
This is getting quite complicated.
I think unless someone makes a strong case for allowing the
combination of the two, disallowing them being combined is probably
the best choice.
cheers
Dan
Ack
This is getting quite complicated.
I think unless someone makes a strong case for allowing the
combination of the two, disallowing them being combined is probably
the best choice.
I'm inclined to agree. There's going to be a lot to understand and agree
on this RFC as it is, so if some edge cases can reasonably be defined as
forbidden, we're less likely to end up regretting some detail.
Then if a good use case is identified, there can be a follow-up RFC,
either within this release cycle, or in a future release.
Regards,
--
Rowan Tommins
[IMSoP]
Hi Larry,
Regarding the syntax, up until now PHP has only supported the letters
a-z and underscore in keywords.I realise this is an aesthetic thing, but "private(set)" looks like a
function to me, and not a keyword. I saw the previous poll, and it
didn't include options for either protected_set/private_set or
protectedset/privateset.Was there a technical reason for excluding them as an option?
Not in particular. We originally proposed private(set)
because that's what Swift uses. In the discussion people proposed several alternatives that I put into the poll, but private_set
wasn't one of them. Although several people said they were opposed to parens in the keyword, the two options that had parens (private(set)
and pubilc(set: private)
) were the leaders for all rounds. I was quite surprised at that, personally; I expected private:set
to do a lot better under the circumstances. But that's not how the poll played out.
--Larry Garfield
Hi Larry,
Regarding the syntax, up until now PHP has only supported the letters
a-z and underscore in keywords.I realise this is an aesthetic thing, but "private(set)" looks like a
function to me, and not a keyword. I saw the previous poll, and it
didn't include options for either protected_set/private_set or
protectedset/privateset.Was there a technical reason for excluding them as an option?
Not in particular. We originally proposed
private(set)
because that's what Swift uses. In the discussion people proposed several alternatives that I put into the poll, butprivate_set
wasn't one of them. Although several people said they were opposed to parens in the keyword,
Have you considered updating the RFC to use private_set, and not
introduce new characters for keywords?
As it wasn't in the poll, then sticking to the poll result with at
least some people saying they are opposed to it seems not necessarily
the correct choice. The ()'s look particularly funky to me with
property promotion.
cheers
Dan
Ack
Hi folks. Ilija is nearly done with the implementation for asymmetric
visibility and flushing out edge cases, but we've run into one design
question we'd like feedback on.There's two design decisions we've made at this point, both of which we
think are logical and reasonable:
If specified, the set visibility must be tighter than the get
visibility. Soprotected protected(set)
andprotected public(set)
are not permitted, for instance.
readonly
is a "write once" flag that may be combined with
asymmetric visibility. If no set visibility is specified,readoly
impliesprivate(set)
, but a different set visibility may also be
provided.These are both reasonable rules. However, it creates a conflict.
Specifically, in the following cases:public public(set) readonly string $foo
protected protected(set) readonly string $foo
These would be the only way to have a non-private-set readonly
property. While the first is in practice quite unlikely, the second
has valid use cases. (In particular, a base class that provides
properties expected to be set by a child constructor, and then used by
a method in the parent class.) However, it would not be allowed under
the rules above. Working around it would require specifyingpublic protected(set) readonly...
, which means exposing a property that
likely should not be exposed.That creates an odd situation where readonly and asymmetric visibility
may only be combined "sometimes." That is not deesireable. The only
way to combine them in their current form is to allowprotected protected(set)
only if readonly is in use, which is excessively
complicated both to implement and to explain/document/use.We see two possible ways to resolve this conflict:
Relax the set-is-tighter restriction. That would allow
protected protected(set)
etc. on any property. It wouldn't be particularly
useful unless readonly is being used, but it would be syntactically
legal and behave as you'd expect. We could still disallow "set is more
permissive" combinations (eg,private public(set)
), as those have no
apparent use case.Disallow readonly and asymmetric visibility being combined, because
readonly already has a hard-coded implied asymmetric visibility. This
option removes some potential use cases (they would most likely drop
the readonly), but has the upside that it's easier to re-allow at some
point in the future.Some other brilliant idea we've not thought of.
Both are viable approaches with pros and cons. We're split on which
way to go with this, so we throw it out to the group for feedback.
Which approach would you favor, or do you have some other brilliant
idea to square this circle?
Thank you everyone for the feedback. Based on this thread, we've made two changes to the RFC:
-
We've moved readonly back to forbidden with a-viz for now. I've added a section to Future Scope where we really should sort this out in the future, but we'll do that in the future when we can all focus on the various nuances of just that piece.
-
I rewrote the section on __set to make it clearer. That also included Ilija and I digging into all the nuances that are already present. The text may still look a bit complex, but that's because the existing logic is already complex with readonly. Long story short, the a-viz RFC does not change anything in the way __set works vis a vis asymmetric visibility; it just inherits and continues what readonly already started, so it's consistent.
The PR should be updated in the next week or two with the latest changes. Baring any major need for change, we expect to call a vote for it shortly after New Years.
Thanks all.
--Larry Garfield
Le 29 nov. 2022 à 21:29, Larry Garfield larry@garfieldtech.com a écrit :
Thank you everyone for the feedback. Based on this thread, we've made two changes to the RFC:
We've moved readonly back to forbidden with a-viz for now. I've added a section to Future Scope where we really should sort this out in the future, but we'll do that in the future when we can all focus on the various nuances of just that piece.
I rewrote the section on __set to make it clearer. That also included Ilija and I digging into all the nuances that are already present. The text may still look a bit complex, but that's because the existing logic is already complex with readonly. Long story short, the a-viz RFC does not change anything in the way __set works vis a vis asymmetric visibility; it just inherits and continues what readonly already started, so it's consistent.
The PR should be updated in the next week or two with the latest changes. Baring any major need for change, we expect to call a vote for it shortly after New Years.
Thanks all.
--Larry Garfield
Hi,
In the RFC, section Permitted visibility (https://wiki.php.net/rfc/asymmetric-visibility#permitted_visibility https://wiki.php.net/rfc/asymmetric-visibility#permitted_visibility):
The set visibility, if it differs from the main (get) visibility, MUST be strictly lesser than the main visibility. That is, the set visibility may only be protected or private. If the main visibility is protected, set visibility may only be private. Any violation of this rule will result in a compile time error.
The first sentence does not forbid public public(set)
, or protected protected(set)
, etc. (the set
visibility does not differ from the main visibility), but the rest of the paragraph does not allow it. That should be clarified.
(Because forbidding public public(set)
, etc., makes it slightly more cumbersome to explain the rules, I am slightly in favour not to forbid it.)
There is one exception, that of a private readonly property. That would technically expand to private private(set) readonly, which is allowed.
That sentence should be deleted, as readonly
is now forbidden.
—Claude
In the RFC, section Permitted visibility
(https://wiki.php.net/rfc/asymmetric-visibility#permitted_visibility
https://wiki.php.net/rfc/asymmetric-visibility#permitted_visibility):The set visibility, if it differs from the main (get) visibility, MUST be strictly lesser than the main visibility. That is, the set visibility may only be protected or private. If the main visibility is protected, set visibility may only be private. Any violation of this rule will result in a compile time error.
The first sentence does not forbid
public public(set)
, orprotected protected(set)
, etc. (theset
visibility does not differ from the
main visibility), but the rest of the paragraph does not allow it. That
should be clarified.
Er. That's exactly what it says: "strictly lesser" than the main visibility. The lines after are just restating it. "public public(set)" is not allowed.
(We may relax that in the future to make it compatible with readonly, but that's for later.)
(Because forbidding
public public(set)
, etc., makes it slightly more
cumbersome to explain the rules, I am slightly in favour not to forbid
it.)There is one exception, that of a private readonly property. That would technically expand to private private(set) readonly, which is allowed.
That sentence should be deleted, as
readonly
is now forbidden.
Good catch, fixed. Thanks.
--Larry Garfield
In the RFC, section Permitted visibility
(https://wiki.php.net/rfc/asymmetric-visibility#permitted_visibility
https://wiki.php.net/rfc/asymmetric-visibility#permitted_visibility):The set visibility, if it differs from the main (get) visibility, MUST be strictly lesser than the main visibility. That is, the set visibility may only be protected or private. If the main visibility is protected, set visibility may only be private. Any violation of this rule will result in a compile time error.
The first sentence does not forbid
public public(set)
, orprotected protected(set)
, etc. (theset
visibility does not differ from the
main visibility), but the rest of the paragraph does not allow it. That
should be clarified.Er. That's exactly what it says: "strictly lesser" than the main visibility. The lines after are just restating it. "public public(set)" is not allowed.
(We may relax that in the future to make it compatible with readonly, but that's for later.)
(Because forbidding
public public(set)
, etc., makes it slightly more
cumbersome to explain the rules, I am slightly in favour not to forbid
it.)There is one exception, that of a private readonly property. That would technically expand to private private(set) readonly, which is allowed.
That sentence should be deleted, as
readonly
is now forbidden.Good catch, fixed. Thanks.
--Larry Garfield
--
To unsubscribe, visit: https://www.php.net/unsub.php
Hi Larry,
Thank you for clarifying the setter behaviour in more explicit terms, but I have to say I’m quite disappointed in this continued “use the logic of readonly to apply to something that is explicitly not readonly” - this is even more stark now that you’ve explicitly made them mutually exclusive behaviours.
I’m generally very in favour of maintaining consistency, but this seems like it’s using technical consistency as an excuse to justify unintuitive behaviour that breaks consistency in another, much more obvious way.
Can you explain why it makes more sense to maintain consistency with “readonly” than it does to maintain consistency with the existing “__set()” behaviour for properties, particularly now that you’ve indicated these features (asymmetric visibility and readonly) are mutually exclusive?
While it’s stated multiple times that “readonly” introduced a limited form of asymmetric visibility, and thus this is a continuation, in terms of intuitiveness, the existing __set() rules are very easy to comprehend even with readonly:
- if the property is declared as public, __set() is never called; if it’s declared as protected, __set is called when the property is accessed from outside that class or it’s hierarchy. Yes, I know that readonly imposes an implicit visibility difference - but that is essentially an implementation detail, from the point of view of the userland developer, it’s not a clear statement of intended behaviour on their part, expressed through the code as written.
For example, with public readonly int $foo
it’s quite obvious why __set() isn’t called, using the exiting well-understood logic: it’s a public property. PHP applies a kind of asymmetric visibility to the property behind the scenes, but that isn’t what the developer declared, it’s the implementation. This behaviour matches that of regular, non-readonly fields: when the field is declared public (or has implicit public visibility) __set() is never called.
If we make that field protected, __set() will be called when the property is written to from outside the class, regardless of whether it’s readonly or not.
What you’re proposing changes that, in a way that is completely unintuitive: when attempting to write data to a property that is marked as protected(set), the __set() method will not be called.
So please, can you explain to me why consistency with an implementation detail of readonly properties is more important than consistency with declared developer intention for regular properties via the magic setter method?
Cheers
Stephen
In the RFC, section Permitted visibility
(https://wiki.php.net/rfc/asymmetric-visibility#permitted_visibility
https://wiki.php.net/rfc/asymmetric-visibility#permitted_visibility):The set visibility, if it differs from the main (get) visibility, MUST
be strictly lesser than the main visibility. That is, the set visibility
may only be protected or private. If the main visibility is protected, set
visibility may only be private. Any violation of this rule will result in a
compile time error.The first sentence does not forbid
public public(set)
, orprotected protected(set)
, etc. (theset
visibility does not differ from the
main visibility), but the rest of the paragraph does not allow it. That
should be clarified.Er. That's exactly what it says: "strictly lesser" than the main
visibility. The lines after are just restating it. "public public(set)"
is not allowed.(We may relax that in the future to make it compatible with readonly,
but that's for later.)(Because forbidding
public public(set)
, etc., makes it slightly more
cumbersome to explain the rules, I am slightly in favour not to forbid
it.)There is one exception, that of a private readonly property. That
would technically expand to private private(set) readonly, which is allowed.That sentence should be deleted, as
readonly
is now forbidden.Good catch, fixed. Thanks.
--Larry Garfield
--
To unsubscribe, visit: https://www.php.net/unsub.php
Hi Larry,
Thank you for clarifying the setter behaviour in more explicit terms, but
I have to say I’m quite disappointed in this continued “use the logic of
readonly to apply to something that is explicitly not readonly” - this is
even more stark now that you’ve explicitly made them mutually exclusive
behaviours.I’m generally very in favour of maintaining consistency, but this seems
like it’s using technical consistency as an excuse to justify unintuitive
behaviour that breaks consistency in another, much more obvious way.Can you explain why it makes more sense to maintain consistency with
“readonly” than it does to maintain consistency with the existing “__set()”
behaviour for properties, particularly now that you’ve indicated these
features (asymmetric visibility and readonly) are mutually exclusive?While it’s stated multiple times that “readonly” introduced a limited form
of asymmetric visibility, and thus this is a continuation, in terms of
intuitiveness, the existing __set() rules are very easy to comprehend even
with readonly:
- if the property is declared as public, __set() is never called; if it’s
declared as protected, __set is called when the property is accessed from
outside that class or it’s hierarchy. Yes, I know that readonly imposes an
implicit visibility difference - but that is essentially an implementation
detail, from the point of view of the userland developer, it’s not a clear
statement of intended behaviour on their part, expressed through the code
as written.For example, with
public readonly int $foo
it’s quite obvious why
__set() isn’t called, using the exiting well-understood logic: it’s a
public property. PHP applies a kind of asymmetric visibility to the
property behind the scenes, but that isn’t what the developer declared,
it’s the implementation. This behaviour matches that of regular,
non-readonly fields: when the field is declared public (or has implicit
public visibility) __set() is never called.If we make that field protected, __set() will be called when the property
is written to from outside the class, regardless of whether it’s readonly
or not.What you’re proposing changes that, in a way that is completely
unintuitive: when attempting to write data to a property that is marked
as protected(set), the __set() method will not be called.So please, can you explain to me why consistency with an implementation
detail of readonly properties is more important than consistency with
declared developer intention for regular properties via the magic setter
method?
Hey, Stephen, Larry,
Just clarifying how I see it:
Practically, the asymmetric visibility for properties is not more or less
than asymmetric write-access for properties.
That is what is implemented, that is what other languages have as well and
this is what's needed.
Of course, except for relation with __set(), unset() and other php
specials, it wouldn't make a difference.
If you think it like this, that property is actually visible but only there
is a restriction on writing it, you would probably agree that __set()
should not be called.
And given that, for clarity, I would be happy if the word visibility would
be changed in the rfc with write-access in various places, including the
rfc name.
But I don't think it's very important, as long as I've understood the
behavior and I can easily explain it going forward.
Regards,
Alex
Cheers
Stephen
--
To unsubscribe, visit: https://www.php.net/unsub.php
In the RFC, section Permitted visibility
(https://wiki.php.net/rfc/asymmetric-visibility#permitted_visibility https://wiki.php.net/rfc/asymmetric-visibility#permitted_visibility
<https://wiki.php.net/rfc/asymmetric-visibility#permitted_visibility https://wiki.php.net/rfc/asymmetric-visibility#permitted_visibility>):The set visibility, if it differs from the main (get) visibility, MUST be strictly lesser than the main visibility. That is, the set visibility may only be protected or private. If the main visibility is protected, set visibility may only be private. Any violation of this rule will result in a compile time error.
The first sentence does not forbid
public public(set)
, orprotected protected(set)
, etc. (theset
visibility does not differ from the
main visibility), but the rest of the paragraph does not allow it. That
should be clarified.Er. That's exactly what it says: "strictly lesser" than the main visibility. The lines after are just restating it. "public public(set)" is not allowed.
(We may relax that in the future to make it compatible with readonly, but that's for later.)
(Because forbidding
public public(set)
, etc., makes it slightly more
cumbersome to explain the rules, I am slightly in favour not to forbid
it.)There is one exception, that of a private readonly property. That would technically expand to private private(set) readonly, which is allowed.
That sentence should be deleted, as
readonly
is now forbidden.Good catch, fixed. Thanks.
--Larry Garfield
--
To unsubscribe, visit: https://www.php.net/unsub.php https://www.php.net/unsub.php
Hi Larry,
Thank you for clarifying the setter behaviour in more explicit terms, but I have to say I’m quite disappointed in this continued “use the logic of readonly to apply to something that is explicitly not readonly” - this is even more stark now that you’ve explicitly made them mutually exclusive behaviours.
I’m generally very in favour of maintaining consistency, but this seems like it’s using technical consistency as an excuse to justify unintuitive behaviour that breaks consistency in another, much more obvious way.
Can you explain why it makes more sense to maintain consistency with “readonly” than it does to maintain consistency with the existing “__set()” behaviour for properties, particularly now that you’ve indicated these features (asymmetric visibility and readonly) are mutually exclusive?
While it’s stated multiple times that “readonly” introduced a limited form of asymmetric visibility, and thus this is a continuation, in terms of intuitiveness, the existing __set() rules are very easy to comprehend even with readonly:
- if the property is declared as public, __set() is never called; if it’s declared as protected, __set is called when the property is accessed from outside that class or it’s hierarchy. Yes, I know that readonly imposes an implicit visibility difference - but that is essentially an implementation detail, from the point of view of the userland developer, it’s not a clear statement of intended behaviour on their part, expressed through the code as written.
For example, with
public readonly int $foo
it’s quite obvious why __set() isn’t called, using the exiting well-understood logic: it’s a public property. PHP applies a kind of asymmetric visibility to the property behind the scenes, but that isn’t what the developer declared, it’s the implementation. This behaviour matches that of regular, non-readonly fields: when the field is declared public (or has implicit public visibility) __set() is never called.If we make that field protected, __set() will be called when the property is written to from outside the class, regardless of whether it’s readonly or not.
What you’re proposing changes that, in a way that is completely unintuitive: when attempting to write data to a property that is marked as protected(set), the __set() method will not be called.
So please, can you explain to me why consistency with an implementation detail of readonly properties is more important than consistency with declared developer intention for regular properties via the magic setter method?
Hey, Stephen, Larry,
Just clarifying how I see it:Practically, the asymmetric visibility for properties is not more or less than asymmetric write-access for properties.
That is what is implemented, that is what other languages have as well and this is what's needed.
Of course, except for relation with __set(), unset() and other php specials, it wouldn't make a difference.If you think it like this, that property is actually visible but only there is a restriction on writing it, you would probably agree that __set() should not be called.
And given that, for clarity, I would be happy if the word visibility would be changed in the rfc with write-access in various places, including the rfc name.
But I don't think it's very important, as long as I've understood the behavior and I can easily explain it going forward.Regards,
AlexCheers
Stephen
--
To unsubscribe, visit: https://www.php.net/unsub.php https://www.php.net/unsub.php
Hi Alex,
No, I do not agree, and I don't think it’s a great sign that you’re suggesting we need to mentally swap out a significant part of what’s written in the RFC for some different concept to have it make sense.
The first paragraph, and the initial section of the proposal make it quite clear that this RFC is about splitting the existing visibility concept into ‘get’ and ’set’ operations.
I find it hard to believe that the authors of the RFC would manage to reference the existing visibility system so many times and in so many ways, if they weren’t explicitly talking about a change related to visibility.
Cheers
Stephen
Hi Larry,
Thank you for clarifying the setter behaviour in more explicit terms,
but I have to say I’m quite disappointed in this continued “use the
logic of readonly to apply to something that is explicitly not
readonly” - this is even more stark now that you’ve explicitly made
them mutually exclusive behaviours.I’m generally very in favour of maintaining consistency, but this seems
like it’s using technical consistency as an excuse to justify
unintuitive behaviour that breaks consistency in another, much more
obvious way.Can you explain why it makes more sense to maintain consistency with
“readonly” than it does to maintain consistency with the existing
“__set()” behaviour for properties, particularly now that you’ve
indicated these features (asymmetric visibility and readonly) are
mutually exclusive?While it’s stated multiple times that “readonly” introduced a limited
form of asymmetric visibility, and thus this is a continuation, in
terms of intuitiveness, the existing __set() rules are very easy to
comprehend even with readonly:
- if the property is declared as public, __set() is never called; if
it’s declared as protected, __set is called when the property is
accessed from outside that class or it’s hierarchy. Yes, I know that
readonly imposes an implicit visibility difference - but that is
essentially an implementation detail, from the point of view of the
userland developer, it’s not a clear statement of intended behaviour on
their part, expressed through the code as written.For example, with
public readonly int $foo
it’s quite obvious why
__set() isn’t called, using the exiting well-understood logic: it’s a
public property. PHP applies a kind of asymmetric visibility to the
property behind the scenes, but that isn’t what the developer declared,
it’s the implementation. This behaviour matches that of regular,
non-readonly fields: when the field is declared public (or has implicit
public visibility) __set() is never called.If we make that field protected, __set() will be called when the
property is written to from outside the class, regardless of whether
it’s readonly or not.What you’re proposing changes that, in a way that is completely
unintuitive: when attempting to write data to a property that is
marked as protected(set), the __set() method will not be called.So please, can you explain to me why consistency with an implementation
detail of readonly properties is more important than consistency with
declared developer intention for regular properties via the magic
setter method?
There's a couple of reasons.
One, and arguably the most important, readonly and aviz being incompatible is, hopefully, a temporary situation. There's some fiddly bits to work out design-wise, and based on earlier comments in the thread we're going to punt on that for now to avoid that dragging down the whole RFC. I believe we absolutely should allow them together in the future (maybe in a later 8.3 RFC, maybe a future version, TBD), which means ensuring, now, that they are compatible in the future. This approach involves the fewest future BC breaks.
Second, I wouldn't call the current behavior of readonly a mere implementation detail. It's weird and unexpected, I'd agree, but only as a side effect of previous design decisions, some of which are even older than readonly. But it's an observed behavior that code can rely on, and in some cases does. For example:
https://peakd.com/hive-168588/@crell/php-tricks-lazy-public-readonly-properties
The "unset a declared property to force it through __get once" is a trick that some ORMs use extensively. readonly just inherited that, leading to the current behavior: __set depends on the write/set visibility of the property and its settedness. This RFC doesn't change anything there.
The alternative would be to have __set called always for a non-public-set property. However, that is a place for bugs, as you then can't not have a back-door way to publicly set a property even if it's declared private(set). (Or, you have to be very careful in your __set to avoid it.) That is both inconsistent with the language today, and error prone.
Finally, we're planning to work in the near-future on property hooks (aka property accessors), which would allow per-property custom set routines. That would largely remove the issue entirely, as the use of __set would go way down and you'd basically never have to use it with a declared property, fancy tricks or no, so this issue would never come up at all.
--Larry Garfield
Hi Larry,
Thank you for clarifying the setter behaviour in more explicit terms,
but I have to say I’m quite disappointed in this continued “use the
logic of readonly to apply to something that is explicitly not
readonly” - this is even more stark now that you’ve explicitly made
them mutually exclusive behaviours.I’m generally very in favour of maintaining consistency, but this seems
like it’s using technical consistency as an excuse to justify
unintuitive behaviour that breaks consistency in another, much more
obvious way.Can you explain why it makes more sense to maintain consistency with
“readonly” than it does to maintain consistency with the existing
“__set()” behaviour for properties, particularly now that you’ve
indicated these features (asymmetric visibility and readonly) are
mutually exclusive?While it’s stated multiple times that “readonly” introduced a limited
form of asymmetric visibility, and thus this is a continuation, in
terms of intuitiveness, the existing __set() rules are very easy to
comprehend even with readonly:
- if the property is declared as public, __set() is never called; if
it’s declared as protected, __set is called when the property is
accessed from outside that class or it’s hierarchy. Yes, I know that
readonly imposes an implicit visibility difference - but that is
essentially an implementation detail, from the point of view of the
userland developer, it’s not a clear statement of intended behaviour on
their part, expressed through the code as written.For example, with
public readonly int $foo
it’s quite obvious why
__set() isn’t called, using the exiting well-understood logic: it’s a
public property. PHP applies a kind of asymmetric visibility to the
property behind the scenes, but that isn’t what the developer declared,
it’s the implementation. This behaviour matches that of regular,
non-readonly fields: when the field is declared public (or has implicit
public visibility) __set() is never called.If we make that field protected, __set() will be called when the
property is written to from outside the class, regardless of whether
it’s readonly or not.What you’re proposing changes that, in a way that is completely
unintuitive: when attempting to write data to a property that is
marked as protected(set), the __set() method will not be called.So please, can you explain to me why consistency with an implementation
detail of readonly properties is more important than consistency with
declared developer intention for regular properties via the magic
setter method?There's a couple of reasons.
One, and arguably the most important, readonly and aviz being incompatible is, hopefully, a temporary situation. There's some fiddly bits to work out design-wise, and based on earlier comments in the thread we're going to punt on that for now to avoid that dragging down the whole RFC. I believe we absolutely should allow them together in the future (maybe in a later 8.3 RFC, maybe a future version, TBD), which means ensuring, now, that they are compatible in the future. This approach involves the fewest future BC breaks.
Second, I wouldn't call the current behavior of readonly a mere implementation detail. It's weird and unexpected, I'd agree, but only as a side effect of previous design decisions, some of which are even older than readonly. But it's an observed behavior that code can rely on, and in some cases does. For example:
https://peakd.com/hive-168588/@crell/php-tricks-lazy-public-readonly-properties
The "unset a declared property to force it through __get once" is a trick that some ORMs use extensively. readonly just inherited that, leading to the current behavior: __set depends on the write/set visibility of the property and its settedness. This RFC doesn't change anything there.
The alternative would be to have __set called always for a non-public-set property. However, that is a place for bugs, as you then can't not have a back-door way to publicly set a property even if it's declared private(set). (Or, you have to be very careful in your __set to avoid it.) That is both inconsistent with the language today, and error prone.
Finally, we're planning to work in the near-future on property hooks (aka property accessors), which would allow per-property custom set routines. That would largely remove the issue entirely, as the use of __set would go way down and you'd basically never have to use it with a declared property, fancy tricks or no, so this issue would never come up at all.
--Larry Garfield
--
To unsubscribe, visit: https://www.php.net/unsub.php
Hi Larry,
I think there must be some confusion somewhere, based on some of your comments.
I’m not suggesting that the “unset to force a public property to go through getter/setter methods” logic should be specifically different.
I’m suggesting that when the decision is made to call __set or not, the properties set visibility is what should be considered, not it’s get visibility.
Your own comment even describes this behaviour: "leading to the current behavior: __set depends on the write/set visibility of the property"
But your RFC says that __set will depend on the read/get visibility of the property.
you then can't not have a back-door way to publicly set a property even if it's declared private(set). (Or, you have to be very careful in your __set to avoid it.) That is both inconsistent with the language today, and error prone.
If a developer adds a _set() method that can write to a private(set) property, I would expect that is working exactly as desired, exactly as it does now where it’s just a “protected” property.
we're planning to work in the near-future on property hooks
That’s great, but I don’t think weird unintuitive behaviour should be added because “well we’re gonna try and solve this through something else later”
Cheers
Stephen
Hi Larry,
Thank you for clarifying the setter behaviour in more explicit terms,
but I have to say I’m quite disappointed in this continued “use the
logic of readonly to apply to something that is explicitly not
readonly” - this is even more stark now that you’ve explicitly made
them mutually exclusive behaviours.I’m generally very in favour of maintaining consistency, but this seems
like it’s using technical consistency as an excuse to justify
unintuitive behaviour that breaks consistency in another, much more
obvious way.Can you explain why it makes more sense to maintain consistency with
“readonly” than it does to maintain consistency with the existing
“__set()” behaviour for properties, particularly now that you’ve
indicated these features (asymmetric visibility and readonly) are
mutually exclusive?While it’s stated multiple times that “readonly” introduced a limited
form of asymmetric visibility, and thus this is a continuation, in
terms of intuitiveness, the existing __set() rules are very easy to
comprehend even with readonly:
- if the property is declared as public, __set() is never called; if
it’s declared as protected, __set is called when the property is
accessed from outside that class or it’s hierarchy. Yes, I know that
readonly imposes an implicit visibility difference - but that is
essentially an implementation detail, from the point of view of the
userland developer, it’s not a clear statement of intended behaviour on
their part, expressed through the code as written.For example, with
public readonly int $foo
it’s quite obvious why
__set() isn’t called, using the exiting well-understood logic: it’s a
public property. PHP applies a kind of asymmetric visibility to the
property behind the scenes, but that isn’t what the developer declared,
it’s the implementation. This behaviour matches that of regular,
non-readonly fields: when the field is declared public (or has implicit
public visibility) __set() is never called.If we make that field protected, __set() will be called when the
property is written to from outside the class, regardless of whether
it’s readonly or not.What you’re proposing changes that, in a way that is completely
unintuitive: when attempting to write data to a property that is
marked as protected(set), the __set() method will not be called.So please, can you explain to me why consistency with an implementation
detail of readonly properties is more important than consistency with
declared developer intention for regular properties via the magic
setter method?There's a couple of reasons.
One, and arguably the most important, readonly and aviz being incompatible is, hopefully, a temporary situation. There's some fiddly bits to work out design-wise, and based on earlier comments in the thread we're going to punt on that for now to avoid that dragging down the whole RFC. I believe we absolutely should allow them together in the future (maybe in a later 8.3 RFC, maybe a future version, TBD), which means ensuring, now, that they are compatible in the future. This approach involves the fewest future BC breaks.
Second, I wouldn't call the current behavior of readonly a mere implementation detail. It's weird and unexpected, I'd agree, but only as a side effect of previous design decisions, some of which are even older than readonly. But it's an observed behavior that code can rely on, and in some cases does. For example:
https://peakd.com/hive-168588/@crell/php-tricks-lazy-public-readonly-properties
The "unset a declared property to force it through __get once" is a trick that some ORMs use extensively. readonly just inherited that, leading to the current behavior: __set depends on the write/set visibility of the property and its settedness. This RFC doesn't change anything there.
The alternative would be to have __set called always for a non-public-set property. However, that is a place for bugs, as you then can't not have a back-door way to publicly set a property even if it's declared private(set). (Or, you have to be very careful in your __set to avoid it.) That is both inconsistent with the language today, and error prone.
Finally, we're planning to work in the near-future on property hooks (aka property accessors), which would allow per-property custom set routines. That would largely remove the issue entirely, as the use of __set would go way down and you'd basically never have to use it with a declared property, fancy tricks or no, so this issue would never come up at all.
--Larry Garfield
--
To unsubscribe, visit: https://www.php.net/unsub.php
Hi Larry,
I think there must be some confusion somewhere, based on some of your comments.
I’m not suggesting that the “unset to force a public property to go through getter/setter methods” logic should be specifically different.
I’m suggesting that when the decision is made to call __set or not, the properties set visibility is what should be considered, not it’s get visibility.
Your own comment even describes this behaviour: "leading to the current behavior: __set depends on the write/set visibility of the property"
But your RFC says that __set will depend on the read/get visibility of the property.
you then can't not have a back-door way to publicly set a property even if it's declared private(set). (Or, you have to be very careful in your __set to avoid it.) That is both inconsistent with the language today, and error prone.
If a developer adds a _set() method that can write to a private(set) property, I would expect that is working exactly as desired, exactly as it does now where it’s just a “protected” property.
we're planning to work in the near-future on property hooks
That’s great, but I don’t think weird unintuitive behaviour should be added because “well we’re gonna try and solve this through something else later”
Cheers
Stephen
--
To unsubscribe, visit: https://www.php.net/unsub.php
Apologies, I meant “where it’s just a private property” rather than “just a protected property” in the second to last sentence.
So please, can you explain to me why consistency with an implementation
detail of readonly properties is more important than consistency with
declared developer intention for regular properties via the magic
setter method?There's a couple of reasons.
One, and arguably the most important, readonly and aviz being incompatible is, hopefully, a temporary situation. There's some fiddly bits to work out design-wise, and based on earlier comments in the thread we're going to punt on that for now to avoid that dragging down the whole RFC. I believe we absolutely should allow them together in the future (maybe in a later 8.3 RFC, maybe a future version, TBD), which means ensuring, now, that they are compatible in the future. This approach involves the fewest future BC breaks.
Second, I wouldn't call the current behavior of readonly a mere implementation detail. It's weird and unexpected, I'd agree, but only as a side effect of previous design decisions, some of which are even older than readonly. But it's an observed behavior that code can rely on, and in some cases does. For example:
https://peakd.com/hive-168588/@crell/php-tricks-lazy-public-readonly-properties
The "unset a declared property to force it through __get once" is a trick that some ORMs use extensively. readonly just inherited that, leading to the current behavior: __set depends on the write/set visibility of the property and its settedness. This RFC doesn't change anything there.
The alternative would be to have __set called always for a non-public-set property. However, that is a place for bugs, as you then can't not have a back-door way to publicly set a property even if it's declared private(set). (Or, you have to be very careful in your __set to avoid it.) That is both inconsistent with the language today, and error prone.
Finally, we're planning to work in the near-future on property hooks (aka property accessors), which would allow per-property custom set routines. That would largely remove the issue entirely, as the use of __set would go way down and you'd basically never have to use it with a declared property, fancy tricks or no, so this issue would never come up at all.
--Larry Garfield
--
To unsubscribe, visit: https://www.php.net/unsub.php
Hi Larry,
I think there must be some confusion somewhere, based on some of your comments.
I’m not suggesting that the “unset to force a public property to go
through getter/setter methods” logic should be specifically different.I’m suggesting that when the decision is made to call __set or not, the
properties set visibility is what should be considered, not it’s
get visibility.Your own comment even describes this behaviour: "leading to the current
behavior: __set depends on the write/set visibility of the property"But your RFC says that __set will depend on the read/get visibility
of the property.you then can't not have a back-door way to publicly set a property even if it's declared private(set). (Or, you have to be very careful in your __set to avoid it.) That is both inconsistent with the language today, and error prone.
If a developer adds a _set() method that can write to a private(set)
property, I would expect that is working exactly as desired, exactly as
it does now where it’s just a “protected” property.
I think we're talking past each other a bit. :-)
The logic described in the RFC is, to the best of out knowledge, what already happens in 8.1/8.2 with readonly. Whether that is good or bad, obvious or intuitive, it's what PHP already does, for better or worse. We view readonly as, effectively, a shorthand for "private(set) write-once" (which is what it is), and want to ensure that future RFCs can do that explicitly so that we can allow public protected(set) readonly
in the future.
For that to be possible, not changing the existing behavior is a necessity. Changing the behavior described in the RFC right now is a BC break. That's true whether the logic described in the RFC is good or not, because that's how it already works with readonly
.
Is it weird that __set depends in part on read visibility? Kinda, yeah. But that's already the behavior in 8.1/8.2. We're not changing anything, and this RFC is not the place to break that kind of BC.
If someone can demonstrate that the logic described there is not what actually happens now, please let us know, because the goal is to not change any behavior in this regard. Effectively, that whole section is descriptive of PHP today and a comment "and we're not breaking it."
--Larry Garfield
Le 30 nov. 2022 à 02:27, Larry Garfield larry@garfieldtech.com a écrit :
In the RFC, section Permitted visibility
(https://wiki.php.net/rfc/asymmetric-visibility#permitted_visibility
https://wiki.php.net/rfc/asymmetric-visibility#permitted_visibility):The set visibility, if it differs from the main (get) visibility, MUST be strictly lesser than the main visibility. That is, the set visibility may only be protected or private. If the main visibility is protected, set visibility may only be private. Any violation of this rule will result in a compile time error.
The first sentence does not forbid
public public(set)
, orprotected protected(set)
, etc. (theset
visibility does not differ from the
main visibility), but the rest of the paragraph does not allow it. That
should be clarified.Er. That's exactly what it says: "strictly lesser" than the main visibility. The lines after are just restating it. "public public(set)" is not allowed.
As I understand the first sentence (what it says, not what you meant):
“The set visibility, if it differs from the main (get) visibility, {$some_restriction}.”
In public public(set)
, the set visibility does not differ from the main/get visibility, therefore {$some_restriction} does not apply.
My guess is that you wanted to say:
“The set visibility, if specified explicitly, {$some_restriction}.”
—Claude
Le 30 nov. 2022 à 02:27, Larry Garfield larry@garfieldtech.com a écrit :
In the RFC, section Permitted visibility
(https://wiki.php.net/rfc/asymmetric-visibility#permitted_visibility
https://wiki.php.net/rfc/asymmetric-visibility#permitted_visibility):The set visibility, if it differs from the main (get) visibility, MUST be strictly lesser than the main visibility. That is, the set visibility may only be protected or private. If the main visibility is protected, set visibility may only be private. Any violation of this rule will result in a compile time error.
The first sentence does not forbid
public public(set)
, orprotected protected(set)
, etc. (theset
visibility does not differ from the
main visibility), but the rest of the paragraph does not allow it. That
should be clarified.Er. That's exactly what it says: "strictly lesser" than the main visibility. The lines after are just restating it. "public public(set)" is not allowed.
As I understand the first sentence (what it says, not what you meant):
“The set visibility, if it differs from the main (get) visibility,
{$some_restriction}.”In
public public(set)
, the set visibility does not differ from the
main/get visibility, therefore {$some_restriction} does not apply.My guess is that you wanted to say:
“The set visibility, if specified explicitly, {$some_restriction}.”
Ahhh... I see what you're getting at. Fair point, I'll adjust it. Thanks.
--Larry Garfield
Hi folks. Ilija is nearly done with the implementation for asymmetric
visibility and flushing out edge cases, but we've run into one design
question we'd like feedback on.There's two design decisions we've made at this point, both of which we
think are logical and reasonable:
If specified, the set visibility must be tighter than the get
visibility. Soprotected protected(set)
andprotected public(set)
are not permitted, for instance.
readonly
is a "write once" flag that may be combined with
asymmetric visibility. If no set visibility is specified,readoly
impliesprivate(set)
, but a different set visibility may also be
provided.These are both reasonable rules. However, it creates a conflict.
Specifically, in the following cases:public public(set) readonly string $foo
protected protected(set) readonly string $foo
These would be the only way to have a non-private-set readonly
property. While the first is in practice quite unlikely, the second
has valid use cases. (In particular, a base class that provides
properties expected to be set by a child constructor, and then used by
a method in the parent class.) However, it would not be allowed under
the rules above. Working around it would require specifyingpublic protected(set) readonly...
, which means exposing a property that
likely should not be exposed.That creates an odd situation where readonly and asymmetric visibility
may only be combined "sometimes." That is not deesireable. The only
way to combine them in their current form is to allowprotected protected(set)
only if readonly is in use, which is excessively
complicated both to implement and to explain/document/use.We see two possible ways to resolve this conflict:
Relax the set-is-tighter restriction. That would allow
protected protected(set)
etc. on any property. It wouldn't be particularly
useful unless readonly is being used, but it would be syntactically
legal and behave as you'd expect. We could still disallow "set is more
permissive" combinations (eg,private public(set)
), as those have no
apparent use case.Disallow readonly and asymmetric visibility being combined, because
readonly already has a hard-coded implied asymmetric visibility. This
option removes some potential use cases (they would most likely drop
the readonly), but has the upside that it's easier to re-allow at some
point in the future.Some other brilliant idea we've not thought of.
Both are viable approaches with pros and cons. We're split on which
way to go with this, so we throw it out to the group for feedback.
Which approach would you favor, or do you have some other brilliant
idea to square this circle?Thank you everyone for the feedback. Based on this thread, we've made
two changes to the RFC:
We've moved readonly back to forbidden with a-viz for now. I've
added a section to Future Scope where we really should sort this out in
the future, but we'll do that in the future when we can all focus on
the various nuances of just that piece.I rewrote the section on __set to make it clearer. That also
included Ilija and I digging into all the nuances that are already
present. The text may still look a bit complex, but that's because the
existing logic is already complex with readonly. Long story short, the
a-viz RFC does not change anything in the way __set works vis a vis
asymmetric visibility; it just inherits and continues what readonly
already started, so it's consistent.The PR should be updated in the next week or two with the latest
changes. Baring any major need for change, we expect to call a vote
for it shortly after New Years.Thanks all.
--Larry Garfield
One other update: Nicolas poked me off list to remind me that the RFC didn't mention inheritance at all. Oops. :-) The patch already has inheritance well handled and tested, it just wasn't described in the RFC. I have added a section that documents the behavior. Short version: You can continue to expand, but not contract, the visibility in child classes, but you can do it for get and set separately. It's pretty much exactly what you'd expect it to do.
--Larry Garfield
Hi,
What is the behaviour of the following code?
class Foo {
public private(set) array $bar = [ ];
}
$foo = new Foo;
$foo->bar['x'] = 'y'; // error?
var_dump(isset($foo->bar['x'])); // true?, false?
I think that modification of an array should require write access? (That should be clarified in the RFC.)
—Claude
Hi,
What is the behaviour of the following code?
class Foo { public private(set) array $bar = [ ]; } $foo = new Foo; $foo->bar['x'] = 'y'; // error? var_dump(isset($foo->bar['x'])); // true?, false?
I think that modification of an array should require write access?
(That should be clarified in the RFC.)
Correct, that would not be allowed. Array writes are always indirect modification, because it's two steps to get to it. That will error out in this case, as one would expect from private(set)
.
--Larry Garfield
Hi
Thank you everyone for the feedback. Based on this thread, we've made two changes to the RFC:
We've moved readonly back to forbidden with a-viz for now. I've added a section to Future Scope where we really should sort this out in the future, but we'll do that in the future when we can all focus on the various nuances of just that piece.
I rewrote the section on __set to make it clearer. That also included Ilija and I digging into all the nuances that are already present. The text may still look a bit complex, but that's because the existing logic is already complex with readonly. Long story short, the a-viz RFC does not change anything in the way __set works vis a vis asymmetric visibility; it just inherits and continues what readonly already started, so it's consistent.
The PR should be updated in the next week or two with the latest changes. Baring any major need for change, we expect to call a vote for it shortly after New Years.
Okay, then I'd like to officially "request" that the abbreviated form
[1] is dropped:
I believe 'protected(set) string $foo' is easily confused with
'protected string $foo' at a simple glance.
Also any implicit rules are something developers will need to learn by
heart, whereas an explicit 'public protected(set) string $foo' could
reasonably be understood by someone without any PHP experience and some
basic experience of OO concepts.
Having two separate explicit keywords also makes it much clearer that
asymmetric visibility is involved, because it's also asymmetric in the code.
I believe the only benefit of the abbreviated form is saving 6
keystrokes (+ one hit to the spacebar) and I don't believe it's worth
the lack of clarity for an important property of the defined property.
Best regards
Tim Düsterhus
[1] https://wiki.php.net/rfc/asymmetric-visibility#abbreviated_form
Hi
Thank you everyone for the feedback. Based on this thread, we've made two changes to the RFC:
We've moved readonly back to forbidden with a-viz for now. I've added a section to Future Scope where we really should sort this out in the future, but we'll do that in the future when we can all focus on the various nuances of just that piece.
I rewrote the section on __set to make it clearer. That also included Ilija and I digging into all the nuances that are already present. The text may still look a bit complex, but that's because the existing logic is already complex with readonly. Long story short, the a-viz RFC does not change anything in the way __set works vis a vis asymmetric visibility; it just inherits and continues what readonly already started, so it's consistent.
The PR should be updated in the next week or two with the latest changes. Baring any major need for change, we expect to call a vote for it shortly after New Years.
Okay, then I'd like to officially "request" that the abbreviated form
[1] is dropped:I believe 'protected(set) string $foo' is easily confused with
'protected string $foo' at a simple glance.Also any implicit rules are something developers will need to learn by
heart, whereas an explicit 'public protected(set) string $foo' could
reasonably be understood by someone without any PHP experience and some
basic experience of OO concepts.Having two separate explicit keywords also makes it much clearer that
asymmetric visibility is involved, because it's also asymmetric in the code.I believe the only benefit of the abbreviated form is saving 6
keystrokes (+ one hit to the spacebar) and I don't believe it's worth
the lack of clarity for an important property of the defined property.Best regards
Tim Düsterhus[1] https://wiki.php.net/rfc/asymmetric-visibility#abbreviated_form
Does anyone else have feelings on this point? IMO, the shorthand makes a lot of sense when used with readonly to avoid lines getting just annoyingly long, but without it I can see the argument for not allowing it; it's about a wash in terms of length with readonly today. I'm comfortable going with the consensus on this one for now.
--Larry Garfield
Hi
Thank you everyone for the feedback. Based on this thread, we've made two changes to the RFC:
We've moved readonly back to forbidden with a-viz for now. I've added a section to Future Scope where we really should sort this out in the future, but we'll do that in the future when we can all focus on the various nuances of just that piece.
I rewrote the section on __set to make it clearer. That also included Ilija and I digging into all the nuances that are already present. The text may still look a bit complex, but that's because the existing logic is already complex with readonly. Long story short, the a-viz RFC does not change anything in the way __set works vis a vis asymmetric visibility; it just inherits and continues what readonly already started, so it's consistent.
The PR should be updated in the next week or two with the latest changes. Baring any major need for change, we expect to call a vote for it shortly after New Years.
Okay, then I'd like to officially "request" that the abbreviated form
[1] is dropped:I believe 'protected(set) string $foo' is easily confused with
'protected string $foo' at a simple glance.Also any implicit rules are something developers will need to learn by
heart, whereas an explicit 'public protected(set) string $foo' could
reasonably be understood by someone without any PHP experience and some
basic experience of OO concepts.Having two separate explicit keywords also makes it much clearer that
asymmetric visibility is involved, because it's also asymmetric in the code.I believe the only benefit of the abbreviated form is saving 6
keystrokes (+ one hit to the spacebar) and I don't believe it's worth
the lack of clarity for an important property of the defined property.Best regards
Tim Düsterhus[1] https://wiki.php.net/rfc/asymmetric-visibility#abbreviated_form
Does anyone else have feelings on this point? IMO, the shorthand makes a lot of sense when used with readonly to avoid lines getting just annoyingly long, but without it I can see the argument for not allowing it; it's about a wash in terms of length with readonly today. I'm comfortable going with the consensus on this one for now.
--Larry Garfield
--
To unsubscribe, visit: https://www.php.net/unsub.php
I’ll just re-iterate what I said in chat a while ago - I think requiring the dev to be explicit about making it public is a safer first step, and it has no BC risk if you wanted to later allow the implicit variant, and without the capability to combine with the readonly keyword (yet) it doesn’t seem like a huge problem to be explicit IMO.
Cheers
Stephen
Le 11 déc. 2022 à 20:18, Larry Garfield larry@garfieldtech.com a écrit :
Hi
Thank you everyone for the feedback. Based on this thread, we've made two changes to the RFC:
We've moved readonly back to forbidden with a-viz for now. I've added a section to Future Scope where we really should sort this out in the future, but we'll do that in the future when we can all focus on the various nuances of just that piece.
I rewrote the section on __set to make it clearer. That also included Ilija and I digging into all the nuances that are already present. The text may still look a bit complex, but that's because the existing logic is already complex with readonly. Long story short, the a-viz RFC does not change anything in the way __set works vis a vis asymmetric visibility; it just inherits and continues what readonly already started, so it's consistent.
The PR should be updated in the next week or two with the latest changes. Baring any major need for change, we expect to call a vote for it shortly after New Years.
Okay, then I'd like to officially "request" that the abbreviated form
[1] is dropped:I believe 'protected(set) string $foo' is easily confused with
'protected string $foo' at a simple glance.Also any implicit rules are something developers will need to learn by
heart, whereas an explicit 'public protected(set) string $foo' could
reasonably be understood by someone without any PHP experience and some
basic experience of OO concepts.Having two separate explicit keywords also makes it much clearer that
asymmetric visibility is involved, because it's also asymmetric in the code.I believe the only benefit of the abbreviated form is saving 6
keystrokes (+ one hit to the spacebar) and I don't believe it's worth
the lack of clarity for an important property of the defined property.Best regards
Tim Düsterhus[1] https://wiki.php.net/rfc/asymmetric-visibility#abbreviated_form
Does anyone else have feelings on this point? IMO, the shorthand makes a lot of sense when used with readonly to avoid lines getting just annoyingly long, but without it I can see the argument for not allowing it; it's about a wash in terms of length with readonly today. I'm comfortable going with the consensus on this one for now.
--Larry Garfield
Hi,
As of today, the following declarations are rejected as syntax errors:
``php
class C {
$a;
int $b;
}
while the following declarations are accepted with implicit `public` visibility:
``php
class C {
static $c;
readonly int $d;
}
It would be reasonable to propose to allow to consistently omit the public
keyword. But allowing to omit it in some cases (including the most controversial one: protected(set)
) and not in other cases...? Because of this inconsistency, people are incited to always write explicitly public
anyway.
—Claude
Le 13 déc. 2022 à 16:34, Claude Pache claude.pache@gmail.com a écrit :
Hi,
As of today, the following declarations are rejected as syntax errors:
class C { $a; int $b; }
while the following declarations are accepted with implicit
public
visibility:class C { static $c; readonly int $d; }
It would be reasonable to propose to allow to consistently omit the
public
keyword. But allowing to omit it in some cases (including the most controversial one:protected(set)
) and not in other cases...? Because of this inconsistency, people are incited to always write explicitlypublic
anyway.—Claude
However, I’m just realising that omitting public
in declarations like public $a
and public int $b
is probably not a good idea, because it is incompatible with constructor property promotion, as function __construct(public int $b) { }
, and function __construct(int $b) { }
have different meanings.
—Claude
Le 13 déc. 2022 à 16:34, Claude Pache claude.pache@gmail.com a écrit :
Hi,
As of today, the following declarations are rejected as syntax errors:
class C { $a; int $b; }
while the following declarations are accepted with implicit
public
visibility:class C { static $c; readonly int $d; }
It would be reasonable to propose to allow to consistently omit the
public
keyword. But allowing to omit it in some cases (including the most controversial one:protected(set)
) and not in other cases...? Because of this inconsistency, people are incited to always write explicitlypublic
anyway.—Claude
However, I’m just realising that omitting
public
in declarations like
public $a
andpublic int $b
is probably not a good idea, because it
is incompatible with constructor property promotion, asfunction __construct(public int $b) { }
, andfunction __construct(int $b) { }
have different meanings.—Claude
Well, it seems the only people who have opinions on the abbreviated form at all dislike it, so we've removed it for now and left a mention in future-scope. A future RFC can add that if desired.
That should, I think, be the final change to the asymmetric visibility RFC. Baring anything else coming up, I expect to call the vote sometime the week of 2 January.
Happy $holiday!
--Larry Garfield
Le 13 déc. 2022 à 16:34, Claude Pache claude.pache@gmail.com a écrit :
Hi,
As of today, the following declarations are rejected as syntax errors:
class C { $a; int $b; }
while the following declarations are accepted with implicit
public
visibility:class C { static $c; readonly int $d; }
It would be reasonable to propose to allow to consistently omit the
public
keyword. But allowing to omit it in some cases (including the most controversial one:protected(set)
) and not in other cases...? Because of this inconsistency, people are incited to always write explicitlypublic
anyway.—Claude
However, I’m just realising that omitting
public
in declarations like
public $a
andpublic int $b
is probably not a good idea, because it
is incompatible with constructor property promotion, asfunction __construct(public int $b) { }
, andfunction __construct(int $b) { }
have different meanings.—Claude
Well, it seems the only people who have opinions on the abbreviated
form at all dislike it, so we've removed it for now and left a mention
in future-scope. A future RFC can add that if desired.That should, I think, be the final change to the asymmetric visibility
RFC. Baring anything else coming up, I expect to call the vote
sometime the week of 2 January.Happy $holiday!
--Larry Garfield
Happy New Year, PHP. Fair warning, I will be opening the vote for asymmetric visibility on Friday, baring any sudden new inputs in the next 40-ish hours.
--Larry Garfield
One quick question,
Will changing the property of a protected/private set via reflection
be allowed? Or will you have to do some shenanigans like you currently
have to do with readonly?
Robert Landers
Software Engineer
Utrecht NL
Le 13 déc. 2022 à 16:34, Claude Pache claude.pache@gmail.com a écrit :
Hi,
As of today, the following declarations are rejected as syntax errors:
class C { $a; int $b; }
while the following declarations are accepted with implicit
public
visibility:class C { static $c; readonly int $d; }
It would be reasonable to propose to allow to consistently omit the
public
keyword. But allowing to omit it in some cases (including the most controversial one:protected(set)
) and not in other cases...? Because of this inconsistency, people are incited to always write explicitlypublic
anyway.—Claude
However, I’m just realising that omitting
public
in declarations like
public $a
andpublic int $b
is probably not a good idea, because it
is incompatible with constructor property promotion, asfunction __construct(public int $b) { }
, andfunction __construct(int $b) { }
have different meanings.—Claude
Well, it seems the only people who have opinions on the abbreviated
form at all dislike it, so we've removed it for now and left a mention
in future-scope. A future RFC can add that if desired.That should, I think, be the final change to the asymmetric visibility
RFC. Baring anything else coming up, I expect to call the vote
sometime the week of 2 January.Happy $holiday!
--Larry Garfield
Happy New Year, PHP. Fair warning, I will be opening the vote for asymmetric visibility on Friday, baring any sudden new inputs in the next 40-ish hours.
--Larry Garfield
--
To unsubscribe, visit: https://www.php.net/unsub.php
Hi Robert
One quick question,
Will changing the property of a protected/private set via reflection
be allowed? Or will you have to do some shenanigans like you currently
have to do with readonly?
Since PHP 8.1 ReflectionProperty::setValue() allows writing to any
property from any scope by default (assuming it is not readonly)
without calling ReflectionProperty::setAccessible() first.
https://wiki.php.net/rfc/make-reflection-setaccessible-no-op
Essentially, there's no change to the existing behavior. You can write
to an asymmetric property using setValue() just like you could to a
protected or private property as the visibility check is skipped for
these cases.
I added a sentence to the RFCs reflection section to clarify.
Thanks for pointing this out.
Ilija