Ilija Tovilo and I would like to offer another RFC for your consideration. It's been a while in coming, and we've evolved the design quite a bit just in the last week so if you saw an earlier draft of it in the past few months, I would encourage you to read it over again to make sure we're all on the same page. I'm actually pretty happy with where it ended up, even if it's not the original design. This approach eliminates several hard-to-implement edge cases while still providing a lot of functionality in one package.
https://wiki.php.net/rfc/property-hooks
--
Larry Garfield
larry@garfieldtech.com
Hi Larry,
pon., 8 maj 2023 o 23:38 Larry Garfield larry@garfieldtech.com napisał(a):
Ilija Tovilo and I would like to offer another RFC for your
consideration. It's been a while in coming, and we've evolved the design
quite a bit just in the last week so if you saw an earlier draft of it in
the past few months, I would encourage you to read it over again to make
sure we're all on the same page. I'm actually pretty happy with where it
ended up, even if it's not the original design. This approach eliminates
several hard-to-implement edge cases while still providing a lot of
functionality in one package.
Using $this->propertyName directly is supported, but not recommended.
Why is that? IMHO in the scope of accessor this is much clearer to me than
using the $field.
The following example does make use of $field, however, and thus a
backing value will be created, and write operations will simply write to
the property as normal.
This looks like new magic to me, whether we allow setting and baking the
value explicitly or not. I consider this behavior confusing.
Overall I vote yes.
Cheers,
Michał Marcin Brzuchalski
Hi
Ilija Tovilo and I would like to offer another RFC for your consideration. It's been a while in coming, and we've evolved the design quite a bit just in the last week so if you saw an earlier draft of it in the past few months, I would encourage you to read it over again to make sure we're all on the same page. I'm actually pretty happy with where it ended up, even if it's not the original design. This approach eliminates several hard-to-implement edge cases while still providing a lot of functionality in one package.
I've read a previous draft and now did another pass through the updated
version:
(1) How does the set() hook interact with #[\SensitiveParameter]?
(2) How will a Stack Trace emitted from a hook look like? Please include
an example of the Exception::__toString() output or so.
(3) ReflectionProperty::getHook(): Will this throw if an invalid hook
name is given or will this return null?
(4) The "Unaffected PHP Functionality" section is empty. It should
either be filled in or removed.
(5) I strongly dislike the doubly abbreviated form of public string $fullName => $this->first . " " . $this->last;
. Having just the extra
'>' in there to distinguish it from a regular property feels non-obvious.
Best regards
Tim Düsterhus
Ilija Tovilo and I would like to offer another RFC for your consideration.
It's been a while in coming, and we've evolved the design quite a bit just
in the last week so if you saw an earlier draft of it in the past few
months, I would encourage you to read it over again to make sure we're all
on the same page. I'm actually pretty happy with where it ended up, even
if it's not the original design. This approach eliminates several
hard-to-implement edge cases while still providing a lot of functionality
in one package.
Congrats for the RFC for property hooks, I like it all, including
abbreviated forms, $value as default name, etc.
Some notes:
- does set($value) { mean set(mixed $value) { or set(TypeFromProp
$value) { ? I understand it would be the latter but it might be nice to
clarify (unless I missed it) - function setFullName => ucfirst is not found in the "set" version
- could parent::$x::set($x) be replaced by parent::$x = $x ? Same for
the get variant? Why not if not? - readonly: could this be supported by materializing them, using the
storage for memoization after first access? that'd be quite powerful - I'm not sure we need ReflectionProperty::getHook('set') when we can
do getHooks()['set'] ?? null - What does ReflectionMethod::getName return on a hook? And getClosure?
- Should we add ReflectionProperty::IS_VIRTUAL ?
- I'm a bit surprised by the possibility of adding attributes to hooks.
I'm not sure I see the use case and I think this might be confusing in
addition to attributes on the property itself. - For serialization: exclude them from
var_export()
andserialize()
,
which don't need virtual props to rebuild the state (you mean
json_encode()
, not JsonSerializable on that list), call get for
var_dump/print_r when it's defined (but ignore exceptions). But (array) /
get_mangled_object_vars()
/get_object_vars()
shouldn't call any "get".
I have a bigger concern: the take on references contradicts with the intro
about BC breaks: turning a materialized property into virtual one would
break BC as far as refs are concerned. One idea to fix that: add a ref
hook, that must return a reference. If not implemented => Error when trying
to get-by-ref. This could also help solve the $foo->array[] case (including
the asym-visiblity issue).
Nicolas
Ilija Tovilo and I would like to offer another RFC for your consideration. It's been a while in coming, and we've evolved the design quite a bit just in the last week so if you saw an earlier draft of it in the past few months, I would encourage you to read it over again to make sure we're all on the same page. I'm actually pretty happy with where it ended up, even if it's not the original design. This approach eliminates several hard-to-implement edge cases while still providing a lot of functionality in one package.
Thanks for all the work that has gone into this. It looks great. The
ability to add properties to interfaces is also really nice.
One thing that concerns me is the following: "the use of [] on any
property (with or without a key) will result in a runtime error being
thrown". While the intent of the RFC is to allow adding hooks without
causing BC breaks, this detail does introduce a BC break. And the break
may get introduced without realizing it.
I'm not sure which solution would be best here: Just accept the
limitations for arrays (same as for list properties in Python) or forbid
the use of hooks for array properties? I'm leaning towards accepting the
limitations, like Python does. Then it is up to the API designer to
decide if a property hook is the right tool for the job or not.
Regards,
Dik
It looks great!
Thank you so, so much. I've been wanting this for a long time. I have used
properties in C# and it's very useful. I'm reading this RFC since it was in
draft. =)
One thing that I did not understand was this piece of code:
class C {
public array $_names;
public string $names {
set {
$this->_prop = explode(',', $value); // <---- Where this
"_prop" is coming from?
}
}
}
$c = new C();
var_dump($c->names = 'Ilija,Larry'); // 'Ilija,Larry'
var_dump($c->_names); // ['Ilija', 'Larry']
Does "_prop" have any special meaning or is it just a typo?
Thanks one more time for this!
Regards,
Erick
Em ter., 9 de mai. de 2023 às 08:52, Dik Takken dik.takken@gmail.com
escreveu:
Ilija Tovilo and I would like to offer another RFC for your
consideration. It's been a while in coming, and we've evolved the design
quite a bit just in the last week so if you saw an earlier draft of it in
the past few months, I would encourage you to read it over again to make
sure we're all on the same page. I'm actually pretty happy with where it
ended up, even if it's not the original design. This approach eliminates
several hard-to-implement edge cases while still providing a lot of
functionality in one package.Thanks for all the work that has gone into this. It looks great. The
ability to add properties to interfaces is also really nice.One thing that concerns me is the following: "the use of [] on any
property (with or without a key) will result in a runtime error being
thrown". While the intent of the RFC is to allow adding hooks without
causing BC breaks, this detail does introduce a BC break. And the break
may get introduced without realizing it.I'm not sure which solution would be best here: Just accept the
limitations for arrays (same as for list properties in Python) or forbid
the use of hooks for array properties? I'm leaning towards accepting the
limitations, like Python does. Then it is up to the API designer to
decide if a property hook is the right tool for the job or not.Regards,
Dik--
To unsubscribe, visit: https://www.php.net/unsub.php
On Mon, May 8, 2023 at 11:38 PM Larry Garfield larry@garfieldtech.com
wrote:
Ilija Tovilo and I would like to offer another RFC for your
consideration. It's been a while in coming, and we've evolved the design
quite a bit just in the last week so if you saw an earlier draft of it in
the past few months, I would encourage you to read it over again to make
sure we're all on the same page. I'm actually pretty happy with where it
ended up, even if it's not the original design. This approach eliminates
several hard-to-implement edge cases while still providing a lot of
functionality in one package.
Thank you! Looks interesting, I will need to think about things before more
qualitative feedback.
An error maybe, the "class C" example in "Detailed Proposal > set" uses a
"$this->_prop", but probably meant to use $this->_names, since private
array $_names; is declared in the example.
I think $field should be its own "chapter". Its a central part of the
proposal that should be clarified early and so that readers don't
accidentally skip it.
I am also confused why $field exists when $this->propertyName works and why
its not recommended to be used. Is $field a reference? or does the "compile
time macro" part mean its replaced at compile time? Ifso, this feels
different to anything else PHP, i am leaning towards $this->propertyName if
there are no other compelling reasons why $field should be used.
--
Larry Garfield
larry@garfieldtech.com--
To unsubscribe, visit: https://www.php.net/unsub.php
Ilija Tovilo and I would like to offer another RFC for your consideration. It's
been a while in coming, and we've evolved the design quite a bit just in the last
week so if you saw an earlier draft of it in the past few months, I would
encourage you to read it over again to make sure we're all on the same page.
I'm actually pretty happy with where it ended up, even if it's not the original
design. This approach eliminates several hard-to-implement edge cases while
still providing a lot of functionality in one package.
+1 from me, I've used it in C# and it makes for clean code and less boilerplate.
-Jeff
Ilija Tovilo and I would like to offer another RFC for your
consideration. It's been a while in coming, and we've evolved the
design quite a bit just in the last week so if you saw an earlier draft
of it in the past few months, I would encourage you to read it over
again to make sure we're all on the same page. I'm actually pretty
happy with where it ended up, even if it's not the original design.
This approach eliminates several hard-to-implement edge cases while
still providing a lot of functionality in one package.
Thanks everyone for your feedback so far. I'm going to collapse the replies into one message to reduce noise.
(1) How does the set() hook interact with #[\SensitiveParameter]?
Internally, the hook is a method, so it should respect it the same way as any other method. Viz, you should be able to write:
public string $foo {
set ($[\SensitiveParameter] string $value) {
$field = strtolower($foo);
}
}
I'll ask Ilija to add a test to confirm that.
(2) How will a Stack Trace emitted from a hook look like? Please include
an example of the Exception::__toString() output or so.
I'll ask Ilija to add a test to his branch and link it here.
(3) ReflectionProperty::getHook(): Will this throw if an invalid hook
name is given or will this return null?
Null if you ask for get/set and one doesn't exist. Error if you ask for something other than "get" or "set". We're still keeping it as a single method, though, to make supporting other hooks easier in the future if desired. I've updated the RFC to clarify that.
(4) The "Unaffected PHP Functionality" section is empty. It should
either be filled in or removed.
Removed. I don't quite understand the purpose of that section. :-)
- does set($value) { mean set(mixed $value) { or set(TypeFromProp
$value) { ? I understand it would be the latter but it might be nice to
clarify (unless I missed it)
Conceptually, I believe it means set(TypeFromProp $value). Since at present that cannot be enforced, though, they're basically the same thing. (If someone with more engine-fu than either of us wants to help enforce contravariant types in set, please speak up because we'd prefer to do so.)
- function setFullName => ucfirst is not found in the "set" version
Yes it is. Look at the end of the set
line.
- could parent::$x::set($x) be replaced by parent::$x = $x ? Same for
the get variant? Why not if not?
There's a subtle but important distinction here. parent::$x would suggest accessing the parent property, ie, its backing value, directly. What is actually intended here is accessing the parent hook, ie, its equivalent to parent::setFoo($foo). The property itself is already available as $field.
We're open to alternate syntaxes for accessing the parent accessor syntax if people have good (and easily implementable) suggestions.
- readonly: could this be supported by materializing them, using the
storage for memoization after first access? that'd be quite powerful
That was one of my early ideas, as it then became a cheap form of cached lazy property. However, that then means there's no meaningful way to unset the cache. In the end we decided that there were too many nooks and crannies to readonly to try and make sense of. (The more I use it, the more I think readonly was a mistake and we should have gone straight to aviz.)
(As a side note, if we had aviz, then we could use the field itself as a cache by making writes private, like so:
public string $name => $field ??= $this->first . $this->last;
But right now that would also imply public-set, which we wouldn't want. Aviz would solve that issue entirely. Another reason aviz is an important and useful feature. :-) )
What a readonly flag on a set-only property means... I have no idea.
- I'm not sure we need ReflectionProperty::getHook('set') when we can
do getHooks()['set'] ?? null
The double-methods were mainly for consistency with the rest of the Reflection API, which tends to have both getFoo(): object and getFoos(): array options. It's no more redundant than the rest of Reflection.
- What does ReflectionMethod::getName return on a hook? And getClosure?
Either "get" or some hashed string that includes "get". I'm not sure off hand. I'll have to check with Ilija.
- Should we add ReflectionProperty::IS_VIRTUAL ?
Funny story. I just asked Ilija this, and he said he already did add it for testing purpose but forgot to tell me. :-) RFC updated.
- I'm a bit surprised by the possibility of adding attributes to hooks.
I'm not sure I see the use case and I think this might be confusing in
addition to attributes on the property itself.
I think in practice it's actually more work not to, since hooks under the hood are just methods like anything else. And as Tim noted above, there are use cases like #[SensitiveParameter] for attributes even down here.
- For serialization: exclude them from
var_export()
andserialize()
,
which don't need virtual props to rebuild the state (you mean
json_encode()
, not JsonSerializable on that list), call get for
var_dump/print_r when it's defined (but ignore exceptions). But (array) /
get_mangled_object_vars()
/get_object_vars()
shouldn't call any "get".
I don't follow. json_encode()
is on the list.
I have a bigger concern: the take on references contradicts with the intro
about BC breaks: turning a materialized property into virtual one would
break BC as far as refs are concerned. One idea to fix that: add a ref
hook, that must return a reference. If not implemented => Error when trying
to get-by-ref. This could also help solve the $foo->array[] case (including
the asym-visiblity issue).
That might be possible. The issue there is that the returned ref would still be bypassing the get/set hooks, so you're just adding a way to dance around the existing hook implementations, which is exactly what we're trying to avoid. Also, what would that hook even mean if used on a virtual property?
Moreover, in practice, getting a reference to a property is extremely rare, with the exception of array writes. I cannot recall the last time I even saw some code get a reference to a property. That's why we felt comfortable just leaving it at is. In an earlier version of the RFC we had a way for properties to just disable references without adding any hooks, but removed it on the grounds that it was not worth the effort.
I'm not sure which solution would be best here: Just accept the
limitations for arrays (same as for list properties in Python) or forbid
the use of hooks for array properties? I'm leaning towards accepting the
limitations, like Python does. Then it is up to the API designer to
decide if a property hook is the right tool for the job or not.
We considered disallowing it on array properties; the problem is, there's also mixed and iterable properties that would have the same challenge, but that couldn't be detected at compile time. That means the runtime check has to be there anyway, so also having a compile-time check for hooks on arrays doesn't really buy us anything but more engine code. So yes, Python-style "just deal with it sunglasses" is the most logical approach.
An error maybe, the "class C" example in "Detailed Proposal > set" uses a
"$this->_prop", but probably meant to use $this->_names, since private
array $_names; is declared in the example.
Yep, typo, thanks. Fixed now.
I think $field should be its own "chapter". Its a central part of the
proposal that should be clarified early and so that readers don't
accidentally skip it.I am also confused why $field exists when $this->propertyName works and why
its not recommended to be used. Is $field a reference? or does the "compile
time macro" part mean its replaced at compile time? Ifso, this feels
different to anything else PHP, i am leaning towards $this->propertyName if
there are no other compelling reasons why $field should be used.
Regarding $field vs. $this->propName, there's a few reasons we went that route.
- It's shorter and less typing for what will be a common pattern.
- That makes it consistent between hook implementations. In working on examples, I found many cases where I was adding basically the same line to multiple hooks on the same class. Making the code easier to copy-paste seems like a win.
- It also will be helpful if hook packages are added in the future, as they'll need a more "generic" way to access the backing property. (See Future Scope.) Eg, "$field = someLogic($value)" applied to a dozen different properties; it wouldn't work if it was "$this->specificProperty = someLogic($value)".
- We're used to our eyes glossing over "$this->propName", as it's so common. Having a separate name to mentally scan for to determine if a property is virtual or not seems like it will be helpful in practice.
- There's precedent for it: Kotlin has almost the same functionality as we describe here, and uses a
field
variable in the exact same way.
So it's mainly an ergonomics argument rather than a technical one. "Compile time macro" means it translates to the same AST as if you'd used $this->propName. There's precedent for that. Constructor Property Promotion works basically the same way.
--Larry Garfield
I have a bigger concern: the take on references contradicts with the intro
about BC breaks: turning a materialized property into virtual one would
break BC as far as refs are concerned. One idea to fix that: add a ref
hook, that must return a reference. If not implemented => Error when trying
to get-by-ref. This could also help solve the $foo->array[] case (including
the asym-visiblity issue).That might be possible. The issue there is that the returned ref would
still be bypassing the get/set hooks, so you're just adding a way to
dance around the existing hook implementations, which is exactly what
we're trying to avoid. Also, what would that hook even mean if used on
a virtual property?Moreover, in practice, getting a reference to a property is extremely
rare, with the exception of array writes. I cannot recall the last
time I even saw some code get a reference to a property. That's why we
felt comfortable just leaving it at is. In an earlier version of the
RFC we had a way for properties to just disable references without
adding any hooks, but removed it on the grounds that it was not worth
the effort.
Addendum here: The RFC wasn't clear, in part because I wasn't clear, but the prohibition on [] on properties applies only on set. On get, whatever array value is returned from the hook is just a boring array, which can then be dereferenced to look up a key.
I've updated the RFC accordingly to make it clearer what is and isn't allowed with arrays.
--Larry Garfield
Regarding $field vs. $this->propName, there's a few reasons we went that route.
- It's shorter and less typing for what will be a common pattern.
- That makes it consistent between hook implementations. In working on examples, I found many cases where I was adding basically the same line to multiple hooks on the same class. Making the code easier to copy-paste seems like a win.
- It also will be helpful if hook packages are added in the future, as they'll need a more "generic" way to access the backing property. (See Future Scope.) Eg, "$field = someLogic($value)" applied to a dozen different properties; it wouldn't work if it was "$this->specificProperty = someLogic($value)".
- We're used to our eyes glossing over "$this->propName", as it's so common. Having a separate name to mentally scan for to determine if a property is virtual or not seems like it will be helpful in practice.
- There's precedent for it: Kotlin has almost the same functionality as we describe here, and uses a
field
variable in the exact same way.So it's mainly an ergonomics argument rather than a technical one. "Compile time macro" means it translates to the same AST as if you'd used $this->propName. There's precedent for that. Constructor Property Promotion works basically the same way.
With using a common name for say, $value, open the door for a library
of common hook implementations (eventually)?
Maybe something like:
class User {
// snip
public string $fullName { get => FancyLibrary\fullName(...) }
// snip
}
I could imagine something like this would be a huge boon to PHP if it
automatically bound the closure.
Regarding $field vs. $this->propName, there's a few reasons we went that route.
- It's shorter and less typing for what will be a common pattern.
- That makes it consistent between hook implementations. In working on examples, I found many cases where I was adding basically the same line to multiple hooks on the same class. Making the code easier to copy-paste seems like a win.
- It also will be helpful if hook packages are added in the future, as they'll need a more "generic" way to access the backing property. (See Future Scope.) Eg, "$field = someLogic($value)" applied to a dozen different properties; it wouldn't work if it was "$this->specificProperty = someLogic($value)".
- We're used to our eyes glossing over "$this->propName", as it's so common. Having a separate name to mentally scan for to determine if a property is virtual or not seems like it will be helpful in practice.
- There's precedent for it: Kotlin has almost the same functionality as we describe here, and uses a
field
variable in the exact same way.So it's mainly an ergonomics argument rather than a technical one. "Compile time macro" means it translates to the same AST as if you'd used $this->propName. There's precedent for that. Constructor Property Promotion works basically the same way.
With using a common name for say, $value, open the door for a library
of common hook implementations (eventually)?Maybe something like:
class User {
// snip
public string $fullName { get => FancyLibrary\fullName(...) }
// snip
}I could imagine something like this would be a huge boon to PHP if it
automatically bound the closure.
$field is only available inside the hook itself, not inside functions called from it. But that does mean you could do this instead:
class User {
// snip
public string $fullName { get => FancyLibrary\fullName($field) }
// snip
}
Which, yes, should work fine.
If such a library actually became popular, that would be an argument to implement the "property hook packages" or "property traits" concept that Swift has, as noted in Future Scope.
--Larry Garfield
Regarding $field vs. $this->propName, there's a few reasons we went that
route.
Overall I think this is a really good proposal, but you might want to
consider a second vote for that particular syntax.
$field
vs $this->propName
feels a little magical. It's a simpler magic
than actual magic methods — it's magic that static analysis tools can
quickly reason about (as they can with promoted properties).
But I can imagine developers coming across this particular syntax in a PR
and thinking "that looks like a bug".
I know it's a few extra keypresses, but I think $this->propName is easier
to scan, and more familiar (given this RFC introduces a lot of other new
syntax).
Ilija Tovilo and I would like to offer another RFC for your consideration. It's been a while in coming, and we've evolved the design quite a bit just in the last week so if you saw an earlier draft of it in the past few months, I would encourage you to read it over again to make sure we're all on the same page. I'm actually pretty happy with where it ended up, even if it's not the original design. This approach eliminates several hard-to-implement edge cases while still providing a lot of functionality in one package.
https://wiki.php.net/rfc/property-hooks
--
Larry Garfield
larry@garfieldtech.com--
To unsubscribe, visit: https://www.php.net/unsub.php
Hi Larry.
public string $fullName => $this->first . " " . $this->last;
-
Suppose that I forgot to declare
$this->first
. Based on the
"deprecate dynamic properties" proposal, will I get an error/warning? -
The shorthand notations supported (the shortest one) creates
impaired syntax, and not pretty to look at for constructor property
promotion.
public function __construct(
public string $prop1 => strtoupper($this->_prop1),
public string $prop2 {set => $field = strtolower($value);},
){}
My suggestion is: use get/set keyword immediately after property
name/default value rather than "=>" or "{" without losing multiline
statements.
public function __construct(
public string $prop1 get => strtoupper($this->_prop1),
public string $prop2 set => $field = strtolower($value),
public string $prop3 get {
$temp = strtoupper($this->_prop1);
return substr($temp, 0, 10) . '...';
}
public string $prop4 set {
$temp = strtolower($value);
$field = substr($temp, 0, 10);
}
){}
This syntax is aligned with a single statement if/for/foreach.
On Mon, May 15, 2023 at 1:41 AM Hendra Gunawan the.liquid.metal@gmail.com
wrote:
- The shorthand notations supported (the shortest one) creates
impaired syntax, and not pretty to look at for constructor property
promotion.
It's starting to get crowded in object constructors. The following example
is so much more readable and maintainable imo. Would it be possible to
still add the quick assignment as a language feature? I'm personally not
happy having property definitions in both the class body and the
constructor signature.
class User {
private string $first;
private string $last;
public string $fullName {
get => $this->first . ' ' . $this->last;
set => [$this->first, $this->last] = explode(' ', $value, 2);
}
public function __construct($this->fullName) {}
}
// vs
class User {
private string $first;
private string $last;
public function __construct(
public string $fullName {
get => $this->first . ' ' . $this->last;
set => [$this->first, $this->last] = explode(' ', $value, 2);
}
) {}
}
// or
class User {
private string $first;
private string $last;
public string $fullName {
get => $this->first . ' ' . $this->last;
set => [$this->first, $this->last] = explode(' ', $value, 2);
}
public function __construct(string $fullName)
{
$this->fullName = $fullName;
}
}
class User { private string $first; private string $last; public string $fullName { get => $this->first . ' ' . $this->last; set => [$this->first, $this->last] = explode(' ', $value, 2); } public function __construct($this->fullName) {} }
Not entirely true, you created redundancy code for $fullName
.
This is why we created constructor property promotion: to eliminate
redundancy.
It's starting to get crowded in object constructors. The following example
is so much more readable and maintainable imo. Would it be possible to
still add the quick assignment as a language feature? I'm personally not
happy having property definitions in both the class body and the
constructor signature.class User { private string $first; private string $last; public string $fullName { get => $this->first . ' ' . $this->last; set => [$this->first, $this->last] = explode(' ', $value, 2); } public function __construct($this->fullName) {} } // vs class User { private string $first; private string $last; public function __construct( public string $fullName { get => $this->first . ' ' . $this->last; set => [$this->first, $this->last] = explode(' ', $value, 2); } ) {} } // or class User { private string $first; private string $last; public string $fullName { get => $this->first . ' ' . $this->last; set => [$this->first, $this->last] = explode(' ', $value, 2); } public function __construct(string $fullName) { $this->fullName = $fullName; } }
The last version skips constructor promotion entirely, so will absolutely work. For this case, that's frankly the best approach, since you're right, the constructor gets rather messy otherwise.
Changing the syntax and semantics for CPP itself (as in the first code block above) is considerably out of scope for this RFC. I recall someone pointing out why double-declaring the property would cause problems, but I forget the reason. In any case, another promotion syntax would be a topic for another RFC. I don't recall off hand the reasons Nikita had for choosing the syntax that ended up being used.
--Larry Garfield
Consolidating all replies into a single message. Please try to keep them together so it's easier to respond to.
(Also, when replying, please please remove duplicate names from the to/cc line. I just got double copies of everything in this thread this morning. I'm on the list, I don't need to be CCed.)
Hi Larry.
public string $fullName => $this->first . " " . $this->last;
- Suppose that I forgot to declare
$this->first
. Based on the
"deprecate dynamic properties" proposal, will I get an error/warning?
Correct, it will behave the same as if you had a fullName() method that accessed an undefined $first property.
- The shorthand notations supported (the shortest one) creates
impaired syntax, and not pretty to look at for constructor property
promotion.public function __construct( public string $prop1 => strtoupper($this->_prop1), public string $prop2 {set => $field = strtolower($value);}, ){}
Well, the first is not really valid anyway. That creates a virtual property with no set hook, which when you pass a value to it in the constructor call will give an error that you are trying to write to a virtual property. So that's already a non-issue.
For the second, the problem with omitting the {} is that it creates yet another syntax variant. That makes it harder for the parser, for static analyzers, for user-space parsing tools like php-parser, etc. That's more work for everyone for fairly little gain.
Removing the {} entirely from all forms makes it harder to denote where the list of hooks begins and ends. They would probably have to be comma-separated, like this:
public string $foo
get { return $this->bar; },
set { $this->bar = $value; };
Which I'd argue is harder to read anyway, because you have to be careful of the very small , and ; marks. The {} is just easier for humans to parse as well as the machine.
Suppose that I just want to cache once and freeze, and I don't want to
create additional hidden property. Please make a judgement on the
validity of this syntax:public string $prop1 { get => $field ??= $this->heavyTask($this->propx, $prop->y); set => null; }
Explanation:
- Since the
get
hook uses$field
, the engine will create a
backing store value with name$prop1
, and will be filled at the
first call only. The later call will use the already stored value.- Since no new value is assigned to
$field
in theset
hook, the value stored in$prop1
is still the same as before.- Since any return statement will be discharged in
set
hook, the
assignment chaining is safe to use and the value which is transferred
is alway the rightmost value (not the value returned by theset
hook).$varx = $obj->prop1 = "hello"; // $varx value is "hello", and $obj->prop1 value is unchanged
An interesting approach. It should work as you describe, but there's two reasons I would discourage it:
- A "set that doesn't set" creates unexpected behavior for callers. If I call set, I expect something to happen. It would be rather confusing to call set and not set things.
- It doesn't actually allow a cache clearing option.
What we really would need here is asymmetric visibility. No set hook, but make the property private(set) so that trying to write to it gives an error, as it should. For cache clearing, the best way to do that is probably with an unset hook. That's been omitted from the RFC for now for simplicity, but that sounds like it would be an argument to introduce it later. Asymmetric visibility would be the higher priority, though.
But, this statement below is NOT ALWAYS correct for "cache once and freeze":
public string $prop1 { set => $field ??= $this->heavyTask($this->propx, $prop->y); }
Explanation:
- Since default
get
hook can be called beforeset
hook,
backing store value with name$prop1
will still be empty.- Otherwise, I have to duplicate the body of the
set
hook into
get
hook to prevent an emptiness backing store.Please give a comment.
Thanks.
Correct; while this syntax would compile, it would result in the value assigned to the property being ignored, and then the other heavyTask() value assigned to it, but that still wouldn't ensure it was available the first time you called get
. That's probably not what anyone wants.
It looks like you answered your own question on the interface point, so I'll leave that be.
--Larry Garfield
(Also, when replying, please please remove duplicate names from the to/cc line. I just got double copies of everything in this thread this morning. I'm on the list, I don't need to be CCed.)
Sorry about that. Not my habit before.
For the second, the problem with omitting the {} is that it creates yet another syntax variant. That makes it harder for the parser, for static analyzers, for user-space parsing tools like php-parser, etc. That's more work for everyone for fairly little gain.
Sad to read that. Making one of them as the shortest shorthand feels
like a picky decision. Some people agree with get
. Some people
will argue that set
deserves more than get
. Personally, I
choose set
to be the shortest shorthand as it is more relevant
with constructor property promotion and value object. Do we need a 2nd
vote for this one?
Removing the {} entirely from all forms makes it harder to denote where the list of hooks begins and ends. They would probably have to be comma-separated, like this:
public string $foo
get { return $this->bar; },
set { $this->bar = $value; };Which I'd argue is harder to read anyway, because you have to be careful of the very small , and ; marks. The {} is just easier for humans to parse as well as the machine.
Looks like it's not more simple compared to the other one.
What we really would need here is asymmetric visibility. No set hook, but make the property private(set) so that trying to write to it gives an error, as it should.
So if asymmetric visibility is implemented, will my code be this simple?
// cache once and freeze,
// and without additional hidden property
public private(set) string $prop1 {
get => $field ??= $this->heavyTask($this->propx, $prop->y);
}
For cache clearing, the best way to do that is probably with an unset hook. That's been omitted from the RFC for now for simplicity, but that sounds like it would be an argument to introduce it later.
I was going to write about this one. IMO, why do we need to provide
additional hidden properties, when we are able to store the cache
directly into it? Obviously we need a unset
hook.
For the second, the problem with omitting the {} is that it creates yet another syntax variant. That makes it harder for the parser, for static analyzers, for user-space parsing tools like php-parser, etc. That's more work for everyone for fairly little gain.
Sad to read that. Making one of them as the shortest shorthand feels
like a picky decision. Some people agree withget
. Some people
will argue thatset
deserves more thanget
. Personally, I
chooseset
to be the shortest shorthand as it is more relevant
with constructor property promotion and value object. Do we need a 2nd
vote for this one?
Secondary votes are generally discouraged. I can see the argument for wanting a short-short version of set, given how common the validation use case is, but => is almost universally the "evaluates to" symbol, so using that for a set operation rather than get just feels weirdly inconsistent. If there were a set-only shorthand, it should be something else.
That said, the ideal for validation would probably be guard clauses, like this, but that would be a completely different RFC for another time.
function foo(string $name where strlen($name) < 10) { ... }
class Foo {
public function __construct(
public string $name where strlen($name) < 10;
) {}
}
What we really would need here is asymmetric visibility. No set hook, but make the property private(set) so that trying to write to it gives an error, as it should.
So if asymmetric visibility is implemented, will my code be this simple?
// cache once and freeze, // and without additional hidden property public private(set) string $prop1 { get => $field ??= $this->heavyTask($this->propx, $prop->y); }
If you don't want cache clearing, yes. Ilija also noted to me off-list that you could also have a set hook that throws an exception rather than just being null, which would also work to prevent writes.
For clearing that cached value, I think an unset hook is probably the best way, with either approach.
For cache clearing, the best way to do that is probably with an unset hook. That's been omitted from the RFC for now for simplicity, but that sounds like it would be an argument to introduce it later.
I was going to write about this one. IMO, why do we need to provide
additional hidden properties, when we are able to store the cache
directly into it? Obviously we need aunset
hook.
I think an unset hook is a fine addition in the future. The way the code is implemented it should be straightforward to add. However, it feels like scope creep to include it right now, especially when there are workarounds available. If there's a clear consensus from voters to include it, though, we can consider that. (Meaning, anyone that would favor including an unset hook now, speak up or we'll assume it's better to stick with just get/set for now.)
--Larry Garfield
Secondary votes are generally discouraged. I can see the argument for wanting a short-short version of set, given how common the validation use case is, but => is almost universally the "evaluates to" symbol, so using that for a set operation rather than get just feels weirdly inconsistent. If there were a set-only shorthand, it should be something else.
That said, the ideal for validation would probably be guard clauses, like this, but that would be a completely different RFC for another time.
function foo(string $name where strlen($name) < 10) { ... } class Foo { public function __construct( public string $name where strlen($name) < 10; ) {} }
guard
seems a subset feature of hook
, although you want to
expand its use case in parameter. Property and parameter are variable.
If guard
can be implemented in both case as you write above,
theoretically hook
can be either. I will choose hook
rather than guard
to anticipate future expansion. Isn't it
better to choose one broad concept than many?
I found a contradiction here. Previously you said that:
... the problem with omitting the {} is that it creates yet another syntax variant. That makes it harder for the parser, for static analyzers, for user-space parsing tools like php-parser, etc. That's more work for everyone for fairly little gain.
And here, you introduce a syntax variant. Is it really significant if
we introduce a new where
keyword compared to the already used
get``` keyword? I will clarify here in case there is
misunderstanding:
- If we have more than one hook per property, then the syntax will be
the same as proposed by RFC. - If we have only one hook per property, than the syntax are:
public function __construct(
public string $prop1 get => strtoupper($this->_prop1),
){}
public function __construct(
public string $prop2 set => $field = strtolower($value),
){}
public function __construct(
public string $prop3 get {
$temp = strtoupper($this->_prop1);
return substr($temp, 0, 10) . '...';
},
){}
public function __construct(
public string $prop4 set {
$temp = strtolower($value);
$field = substr($temp, 0, 10);
},
){}
Note: Please ignore any error. The ending comma is actually part of
the parameter list, not a hook. So it becomes optional if the param is
only one or it is the last param.
All the examples are constructor property promotion, because that is
my only concern. Because the space is limited, the more consistent the
code, the better. If I have to write hooks outside CPP, I don't mind
using the other syntax. There's plenty of room to fill, and
consistency is tolerable.
Should we postpone the implementation of the shortest version?
Hopefully we have enough time to decide which one will be implemented
next.
... Ilija also noted to me off-list that you could also have a set hook that throws an exception rather than just being null, which would also work to prevent writes.
Such a coincidence. I was going to revise my code:
// cache once and freeze,
// and without additional hidden property
// in case asymmetric visibility in not implemented yet
public string $prop1 {
get => $field ??= $this->heavyTask($this->propx, $prop->y);
set => throw new Exception("prop1 is read only");
}
I think an unset hook is a fine addition in the future. The way the code is implemented it should be straightforward to add. However, it feels like scope creep to include it right now, especially when there are workarounds available. If there's a clear consensus from voters to include it, though, we can consider that. (Meaning, anyone that would favor including an unset hook now, speak up or we'll assume it's better to stick with just get/set for now.)
+1 for including unset
as part of this RFC.
Ilija Tovilo and I would like to offer another RFC for your consideration. It's been a while in coming, and we've evolved the design quite a bit just in the last week so if you saw an earlier draft of it in the past few months, I would encourage you to read it over again to make sure we're all on the same page. I'm actually pretty happy with where it ended up, even if it's not the original design. This approach eliminates several hard-to-implement edge cases while still providing a lot of functionality in one package.
https://wiki.php.net/rfc/property-hooks
--
Larry Garfield
larry@garfieldtech.com--
To unsubscribe, visit: https://www.php.net/unsub.php
Hi Larry.
Suppose that I just want to cache once and freeze, and I don't want to
create additional hidden property. Please make a judgement on the
validity of this syntax:
public string $prop1 {
get => $field ??= $this->heavyTask($this->propx, $prop->y);
set => null;
}
Explanation:
- Since the
get
hook uses$field
, the engine will create a
backing store value with name$prop1
, and will be filled at the
first call only. The later call will use the already stored value. - Since no new value is assigned to
$field
in theset
hook, the value stored in$prop1
is still the same as before. - Since any return statement will be discharged in
set
hook, the
assignment chaining is safe to use and the value which is transferred
is alway the rightmost value (not the value returned by theset
hook).
$varx = $obj->prop1 = "hello"; // $varx value is "hello", and
$obj->prop1 value is unchanged
But, this statement below is NOT ALWAYS correct for "cache once and freeze":
public string $prop1 {
set => $field ??= $this->heavyTask($this->propx, $prop->y);
}
Explanation:
- Since default
get
hook can be called beforeset
hook,
backing store value with name$prop1
will still be empty. - Otherwise, I have to duplicate the body of the
set
hook into
get
hook to prevent an emptiness backing store.
Please give a comment.
Thanks.
Ilija Tovilo and I would like to offer another RFC for your consideration. It's been a while in coming, and we've evolved the design quite a bit just in the last week so if you saw an earlier draft of it in the past few months, I would encourage you to read it over again to make sure we're all on the same page. I'm actually pretty happy with where it ended up, even if it's not the original design. This approach eliminates several hard-to-implement edge cases while still providing a lot of functionality in one package.
https://wiki.php.net/rfc/property-hooks
--
Larry Garfield
larry@garfieldtech.com
Hi, Larry
interface IFace
{
public string $readable { get; }
public string $writeable { set; }
public string $both { get; set; }
}
How important is { get; }
statement (and friends) in the interface?
Since PHP does not enforce method definition existence in caller site,
this code is valid (at least at compile time):
interface IA {
// ...
}
interface IB {
public function doIt(IA $par1);
}
class CA1 implements IA {
// makeIt is not part of IA
public function makeIt() {
echo " makeIt() is called";
}
}
class CA2 implements IA {}
class CB implements IB {
public function doit(IA $par1) {
// makeIt is not enforced to be invalid
$par1->makeit();
}
}
$a1 = new CA1;
$a2 = new CA2;
$b = new CB;
$b->doIt($a1); // valid
$b->doIt($a2); // invalid at runtime
IMO, { get; }
(and friends) only useful if there are:
- definition existence enforcement or implemented asymmetric visibility
- AND no default hook implementation provided.
I assume that { get; }
do exist in the property accessors
proposal because there is no default hook implementation. Whether
there is already implemented property definition existence enforcement
or not, i don't know. If yes, then all things are in the right place.
If not, it feels like a half baked feature, just like the method was:
the error will pop up at runtime. The only positive value is { get; }
can still be consumed by static analysis tools.
class CX {
public function consumeIt(IFace $par) {
// this statement should trigger error
// produced by engine or SA tools
$par->readable = "hello";
}
}
Things will be different with property hooks. Without definition
existence enforcement nor implemented asymmetric visibility, static
analysis tools will give misconception about unlisted hooks if there
is error/warning message.
class CX {
public function consumeIt(IFace $par) {
// default hook is provided by engine
// any message is not relevant for this valid statement
$par->readable = "hello";
}
}
If there is no forward compatibility consideration, can we simplify
interface definition to this one?
interface IFace
{
public string $readable;
public string $writeable;
public string $both;
}
Thanks in advance.
If there is no forward compatibility consideration, can we simplify
interface definition to this one?interface IFace { public string $readable; public string $writeable; public string $both; }
After carefully reading the proposal again, I think I know the answer
for my own question.
Short answer: no, we still need { get; }
to enforce the implemented class.
There are two different things here:
- enforcing the implemented class
- enforcing the caller site
If there are only ordinary properties, then { get; }
is truly
useless at the moment. On the other hand, virtual properties need
rules to be enforced, since there is no default hook given to it.
Since PHP lacks method definition enforcement at the caller site, I
assume that property would suffer the same.
Since we don't know what type of property is in the caller site,
static analysis tools can benefit from { get; }
to produce a
warning that we should not assign value to the property. A more
complex check should be performed to the implemented class because the
property type can be determined directly (if i am not wrong).
interface IFace
{
public string $readable1 { get; }
public string $readable2 { get; }
}
class CX implements IFace {
private string $_propx;
public string $readable1;
public string $readable2 {
get => $this->_propx;
set => $this->_propx = $value;
}
public function consumeIt(IFace $par) {
// these statements should trigger warning by SA tools
$par->readable1 = "hello";
$par->readable2 = "world";
// OK
$this->readable1 = "hello";
// this statement should trigger error by SA tools
$this->readable2 = "hello";
}
}
Ilija Tovilo and I would like to offer another RFC for your consideration. It's been a while in coming, and we've evolved the design quite a bit just in the last week so if you saw an earlier draft of it in the past few months, I would encourage you to read it over again to make sure we're all on the same page. I'm actually pretty happy with where it ended up, even if it's not the original design. This approach eliminates several hard-to-implement edge cases while still providing a lot of functionality in one package.
https://wiki.php.net/rfc/property-hooks
--
Larry Garfield
larry@garfieldtech.com
Hi Larry
Can the engine detect these logical errors?
public string $fullName = "hendra gunawan" => $this->first . " " . $this->last;
// or with my proposal:
public string $fullName = "hendra gunawan" get => $this->first . " " .
$this->last;
// or even this one:
public string $fullName = "hendra gunawan" {
get => $this->first . " " . $this->last;
set => [$this->first, $this->last] = explode(" ", $value);
Explanation:
There is no automatic backing store value created to store the default value.
Terima Kasih.
Missed one...
Can the engine detect these logical errors?
public string $fullName = "hendra gunawan" => $this->first . " " . $this->last; // or with my proposal: public string $fullName = "hendra gunawan" get => $this->first . " " . $this->last; // or even this one: public string $fullName = "hendra gunawan" { get => $this->first . " " . $this->last; set => [$this->first, $this->last] = explode(" ", $value);
Explanation:
There is no automatic backing store value created to store the default value.Terima Kasih.
Those would be compile-time syntax errors, yes. (Or possibly link time, if inheritance is involved, but still before execution time.)
--Larry Garfield
Ilija Tovilo and I would like to offer another RFC for your
consideration. It's been a while in coming, and we've evolved the
design quite a bit just in the last week so if you saw an earlier draft
of it in the past few months, I would encourage you to read it over
again to make sure we're all on the same page. I'm actually pretty
happy with where it ended up, even if it's not the original design.
This approach eliminates several hard-to-implement edge cases while
still providing a lot of functionality in one package.
Hi folks. Based on feedback we've made a few smaller changes to the RFC.
Changelog:
-
The sections describing isset/unset and magic methods have been rewritten to be clearer. Nothing changed in the actual behavior, it is now just explained better.
-
Contravariance on the "set" type is now enforced. Ilija figured out how to make it work. :-) That means a non-contravariant type on the set hook will now throw an error, as expected.
-
After extensive discussion with Nicolas Grekas, we've decided to allow references in a very narrow case. Specifically, on a virtual property (one that has no inherent backing store), you may implement a
&get
hook instead ofget
, and the value it returns will be returned by reference, and may be captured using $foo =& $bar->baz; We determined that it is a bit better for BC (in the rare cases that you actually want to get a reference to a property, you can, even if it requires a little more work), doesn't break anything else, and is consistent with the way&__get
behaves. __get/__set are basically "anonymous virtual properties", so now they behave the same way. By the same token, setting by reference is still not allowed, which is also true for __set today.
As there was no other interest in it stated, we're going to hold off on an unset
hook at this time. Given the earlier discussion I think there is a valid use case for it, so it would be a worthwhile follow up RFC in the future, but for the moment we want to keep it simple.
There also doesn't seem to be much interest in specifying which hook gets the double-shortened syntax. I can see the argument for it, but it would increase the typing in a common case for an unclear benefit, and only one person expressed any interest in it. So we're not going to go that route.
There's two items still pending.
-
Ilija is experimenting with the
parent::$prop::get()
syntax, to see if either the syntax or implementation can be simplified. There may or may not be a small change here as a result, TBD. -
Ilija still has to verify that foreach() can work with virtual properties as the RFC currently describes. The implementation details are thornier than they seem, so that still needs some validation and testing.
Assuming both of those get sorted out soon, we will probably call a vote around the end of the month, give or take.
Cheers.
--Larry Garfield
I can't wait!
Especially because I'm heading a modernization of the systems in my
organization and my plan is to use the cutting edge PHP version for it.
Currently our internal "framework" uses PHP 7.4, but with a PHP 5.6 coding
style.
Again: I can't wait!
I can't do much but thank everyone who spends their time to make PHP evolve.
Thank you all!
Regards,
Erick
Em sex., 19 de mai. de 2023 às 17:48, Larry Garfield larry@garfieldtech.com
escreveu:
Ilija Tovilo and I would like to offer another RFC for your
consideration. It's been a while in coming, and we've evolved the
design quite a bit just in the last week so if you saw an earlier draft
of it in the past few months, I would encourage you to read it over
again to make sure we're all on the same page. I'm actually pretty
happy with where it ended up, even if it's not the original design.
This approach eliminates several hard-to-implement edge cases while
still providing a lot of functionality in one package.Hi folks. Based on feedback we've made a few smaller changes to the RFC.
Changelog:
The sections describing isset/unset and magic methods have been
rewritten to be clearer. Nothing changed in the actual behavior, it is now
just explained better.Contravariance on the "set" type is now enforced. Ilija figured out how
to make it work. :-) That means a non-contravariant type on the set hook
will now throw an error, as expected.After extensive discussion with Nicolas Grekas, we've decided to allow
references in a very narrow case. Specifically, on a virtual property
(one that has no inherent backing store), you may implement a&get
hook
instead ofget
, and the value it returns will be returned by reference,
and may be captured using $foo =& $bar->baz; We determined that it is a
bit better for BC (in the rare cases that you actually want to get a
reference to a property, you can, even if it requires a little more work),
doesn't break anything else, and is consistent with the way&__get
behaves. __get/__set are basically "anonymous virtual properties", so now
they behave the same way. By the same token, setting by reference is still
not allowed, which is also true for __set today.As there was no other interest in it stated, we're going to hold off on an
unset
hook at this time. Given the earlier discussion I think there is a
valid use case for it, so it would be a worthwhile follow up RFC in the
future, but for the moment we want to keep it simple.There also doesn't seem to be much interest in specifying which hook gets
the double-shortened syntax. I can see the argument for it, but it would
increase the typing in a common case for an unclear benefit, and only one
person expressed any interest in it. So we're not going to go that route.There's two items still pending.
Ilija is experimenting with the
parent::$prop::get()
syntax, to see
if either the syntax or implementation can be simplified. There may or may
not be a small change here as a result, TBD.Ilija still has to verify that foreach() can work with virtual
properties as the RFC currently describes. The implementation details are
thornier than they seem, so that still needs some validation and testing.Assuming both of those get sorted out soon, we will probably call a vote
around the end of the month, give or take.Cheers.
--Larry Garfield
--
To unsubscribe, visit: https://www.php.net/unsub.php
Le 8 mai 2023 à 23:38, Larry Garfield larry@garfieldtech.com a écrit :
Ilija Tovilo and I would like to offer another RFC for your consideration. It's been a while in coming, and we've evolved the design quite a bit just in the last week so if you saw an earlier draft of it in the past few months, I would encourage you to read it over again to make sure we're all on the same page. I'm actually pretty happy with where it ended up, even if it's not the original design. This approach eliminates several hard-to-implement edge cases while still providing a lot of functionality in one package.
Hi,
If I understand correctly, given:
<?php
class C {
public int $someInt;
public float $someFloat;
public int $someIntWithHook {
get => $field;
set => $field = $value;
}
public float $someFloatWithHook {
get => $field;
set => $field = $value;
}
}
?>
we have:
<?php
$obj = new C;
var_dump($obj->someInt = 42.0); // int(42)
var_dump($obj->someFloat = 42); // float(42)
?>
but:
<?php
$obj = new C;
var_dump($obj->someIntWithHook = 42.0); // float(42)
var_dump($obj->someFloatWithHook = 42); // int(42)
?>
If I am correct, it means that the “This also implies that adding a set hook to a property cannot change the result of the = operator” statement is a bit too optimistic.
—Claude
--
Larry Garfield
larry@garfieldtech.com
Le 8 mai 2023 à 23:38, Larry Garfield larry@garfieldtech.com a écrit :
Ilija Tovilo and I would like to offer another RFC for your consideration. It's been a while in coming, and we've evolved the design quite a bit just in the last week so if you saw an earlier draft of it in the past few months, I would encourage you to read it over again to make sure we're all on the same page. I'm actually pretty happy with where it ended up, even if it's not the original design. This approach eliminates several hard-to-implement edge cases while still providing a lot of functionality in one package.
Hi,
If I understand correctly, given:
<?php
class C {
public int $someInt; public float $someFloat; public int $someIntWithHook { get => $field; set => $field = $value; } public float $someFloatWithHook { get => $field; set => $field = $value; }
}
?>we have:
<?php
$obj = new C;
var_dump($obj->someInt = 42.0); // int(42)
var_dump($obj->someFloat = 42); // float(42)
?>but:
<?php
$obj = new C;
var_dump($obj->someIntWithHook = 42.0); // float(42)
var_dump($obj->someFloatWithHook = 42); // int(42)
?>If I am correct, it means that the “This also implies that adding a set
hook to a property cannot change the result of the = operator”
statement is a bit too optimistic.
We looked into this a bit; it's correct if you're in weak mode. In strict mode, it applies only to $o->float = $anInt, as that's the only legal type coercion. Still, you're right that it's not quite "cannot change", so I've adjusted the wording to better describe the edge cases. The behavior is still the same as __set(), so we don't see a need to change it further.
Thanks for the catch.
--Larry Garfield
Hey everyone.
Any news on this? I'm really excited about this one. =)
--
Erick de Azevedo Lima
Em ter., 30 de mai. de 2023 às 14:15, Larry Garfield larry@garfieldtech.com
escreveu:
--
Larry Garfield
larry@garfieldtech.comLe 8 mai 2023 à 23:38, Larry Garfield larry@garfieldtech.com a écrit
:Ilija Tovilo and I would like to offer another RFC for your
consideration. It's been a while in coming, and we've evolved the design
quite a bit just in the last week so if you saw an earlier draft of it in
the past few months, I would encourage you to read it over again to make
sure we're all on the same page. I'm actually pretty happy with where it
ended up, even if it's not the original design. This approach eliminates
several hard-to-implement edge cases while still providing a lot of
functionality in one package.Hi,
If I understand correctly, given:
<?php
class C {
public int $someInt; public float $someFloat; public int $someIntWithHook { get => $field; set => $field = $value; } public float $someFloatWithHook { get => $field; set => $field = $value; }
}
?>we have:
<?php
$obj = new C;
var_dump($obj->someInt = 42.0); // int(42)
var_dump($obj->someFloat = 42); // float(42)
?>but:
<?php
$obj = new C;
var_dump($obj->someIntWithHook = 42.0); // float(42)
var_dump($obj->someFloatWithHook = 42); // int(42)
?>If I am correct, it means that the “This also implies that adding a set
hook to a property cannot change the result of the = operator”
statement is a bit too optimistic.We looked into this a bit; it's correct if you're in weak mode. In strict
mode, it applies only to $o->float = $anInt, as that's the only legal type
coercion. Still, you're right that it's not quite "cannot change", so I've
adjusted the wording to better describe the edge cases. The behavior is
still the same as __set(), so we don't see a need to change it further.Thanks for the catch.
--Larry Garfield
--
To unsubscribe, visit: https://www.php.net/unsub.php
Ilija Tovilo and I would like to offer another RFC for your
consideration. It's been a while in coming, and we've evolved the
design quite a bit just in the last week so if you saw an earlier draft
of it in the past few months, I would encourage you to read it over
again to make sure we're all on the same page. I'm actually pretty
happy with where it ended up, even if it's not the original design.
This approach eliminates several hard-to-implement edge cases while
still providing a lot of functionality in one package.https://wiki.php.net/rfc/property-hooks
--
Larry Garfield
larry@garfieldtech.com
Hi all.
Ilija was unfortunately hit with multiple technology failures this month, which slowed down final development of the hooks proposal. While we’re pretty comfortable and happy with the design at this point (and it seems most people in the discussion thread are as well), Ilija is concerned about passing it this close to feature freeze, on the off chance that some undiscovered implementation detail may necessitate a small API change (and thus another RFC).
Given the timing, therefore, we’re also going to delay the vote until later this summer (probably), after Ilija’s had time to bang on the implementation a bit further to make sure there’s no hidden gotchas. That will unfortunately push it to the 8.4 cycle. On the upside, that will give it a very long settling-in time so that by the time it shows up in a stable version it’s rock solid.
Thanks for sticking with us. We’ll provide another update when Ilija’s comfortable with the state of the implementation.
--Larry Garfield
Thanks for the feedback.
I hope everything works well for Ilija. Thank you also for the good work
you have done.
--
Erick de Azevedo Lima
Em dom., 2 de jul. de 2023 às 09:52, Larry Garfield larry@garfieldtech.com
escreveu:
Ilija Tovilo and I would like to offer another RFC for your
consideration. It's been a while in coming, and we've evolved the
design quite a bit just in the last week so if you saw an earlier draft
of it in the past few months, I would encourage you to read it over
again to make sure we're all on the same page. I'm actually pretty
happy with where it ended up, even if it's not the original design.
This approach eliminates several hard-to-implement edge cases while
still providing a lot of functionality in one package.https://wiki.php.net/rfc/property-hooks
--
Larry Garfield
larry@garfieldtech.comHi all.
Ilija was unfortunately hit with multiple technology failures this month,
which slowed down final development of the hooks proposal. While we’re
pretty comfortable and happy with the design at this point (and it seems
most people in the discussion thread are as well), Ilija is concerned about
passing it this close to feature freeze, on the off chance that some
undiscovered implementation detail may necessitate a small API change (and
thus another RFC).Given the timing, therefore, we’re also going to delay the vote until
later this summer (probably), after Ilija’s had time to bang on the
implementation a bit further to make sure there’s no hidden gotchas. That
will unfortunately push it to the 8.4 cycle. On the upside, that will give
it a very long settling-in time so that by the time it shows up in a stable
version it’s rock solid.Thanks for sticking with us. We’ll provide another update when Ilija’s
comfortable with the state of the implementation.--Larry Garfield
--
To unsubscribe, visit: https://www.php.net/unsub.php