[PHP-DEV] [RFC] [VOTE] Deprecate implicitly nullable parameter types
Hello internals, I have opened the vote for the "Deprecate implicitly nullable parameter types" RFC: https://wiki.php.net/rfc/deprecate-implicitly-nullable-types It will run for two weeks until the 13th of March 2024. Best regards, Gina P. Banyard
Re: [PHP-DEV] [RFC[ Property accessor hooks, take 2
On Tuesday, 27 February 2024 at 23:17, Larry Garfield wrote: > I genuinely don't understand the pushback on $value. It's something you learn > once and never have to think about again. It's consistent. > > Ilija jokingly suggested making it always $value, unconditionally, and > allowing only the type to be specified if widening: > > public int $foo { set(int|float) => floor($value); } > > > Though I suspect that won't go over well, either. :-) Same, I don't understand the pushback on $value, for me this seems clearer and less confusing than the existing $this variable when I was first learning about OOP. And I would be in favour of just making it always $value, if people feel that strongly about being able to name it with a custom name they could propose this as a follow-up RFC. One thing the RFC should note, which I would expect to be the same as the array cast, is how do backed/virtual properties interact with get_mangled_object_vars() Best regards, Gina P. Banyard
Re: [PHP-DEV] [RFC[ Property accessor hooks, take 2
On Wed, Feb 28, 2024, at 7:49 AM, Stephen Reay wrote: *snip* >> == Re virtual properties: >> >> Ilija and I talked this through, and there's pros and cons to a `virtual` >> keyword. Ilija also suggested a `backed` keyword, which forces a backed >> property to exist even if it's not used in the hook itself. >> >> * Adding `virtual` adds more work for the developer, but more clarity. It >> would also mean $this->$propName or $this->{__PROPERTY__} would work "as >> expected", since there's no auto-detection for virtual-ness. On the >> downside, if you have a could-be-virtual property but never actually use the >> backing value, you have an extra backing value hanging around in memory that >> is inaccessible normally, but will still show up in some serialization >> formats, which could be unexpected. If you omit one of the hooks and forget >> to mark it virtual, you'll still get the default of the other operation, >> which could be unexpected. (Mostly this would be for a virtual-get that >> accidentally has a default setter because you forgot to mark it `virtual`.) >> * Doing autodetection as now, but with an added "make a backing value >> anyway" flag would resolve the use case of "My set hook just calls a method, >> and that method sets the property, but since the hook doesn't mention the >> property it doesn't get created" problem. It would also allow for >> $this->$propName to work if a property is explicitly backed. On the >> flipside, it's one more thing to think about, and the above example it >> solves would be trivially solved by having the method just return the value >> to set and letting the set hook do the actual write, which is arguably >> better and more reliable code anyway. >> * The status quo (auto-detection based on the presence of $this->propName). >> This has the advantage it "just works" in the 95% case, without having to >> think about anything extra. The downside is it does have some odd edge >> cases, like needing $this->propName to be explicitly used. >> >> I don't think any is an obvious winner. My personal preference would be for >> status quo (auto-detect) or explicit-virtual always. I could probably live >> with either, though I think I'd personally favor status quo. Thoughts from >> others? >> > > I agree that a flag to make the field *virtual* (thus disabling the > backing store) makes more sense than a flag to make it backed; It's > also easier to understand when comparing hooked properties with regular > properties (essentially, backed is the default, you have to opt-in to > it being virtual). I don't think the edge cases of "auto" make it > worthwhile just to not need "virtual". Uh, I can't tell if you're saying "use status quo" or "use the virtual keyword." Please clarify. :-) >> == Re reference-get >> >> Allowing backed properties to have a reference return creates a situation >> where any writes would then bypass the set hook, and thus any validation >> implemented there. That is, it makes the validation unreliable. A major >> footgun. The question is, do we favor caveat-emptor flexibility or >> correct-by-construction safety? Personally I always lead toward the latter, >> though PHP in general is... schizophrenic about it, I'd say. :-) >> >> At this point, we'd much rather leave it blocked to avoid the issue; it's >> easier to enable that loophole in the future if we really want it than to >> get rid of it if it turns out to have been a bad idea. >> >> There is one edge case that *might* make sense: If there is no set hook >> defined, then there's no set hook to worry about bypassing. So it may be >> safe to allow on backed properties IFF there is no set hook. I worry >> that is "one more quirky edge case", though, so as above it may be better to >> skip for now as it's easier to add later than remove. But if the consensus >> is to do that, we're open to it. (Question for everyone.) >> > > I don't have strong feeling about this, but in general I usually tend > to prefer options that are consistent, and give power/options to the > developer. If references are opt-in anyway, I see that as accepting the > trade-offs. If a developer doesn't want to allow by-ref modifications > of the property, why would they make it referenceable in the first > place? This sounds a bit like disallowing regular public properties > because they might be modified outside the class - that's kind of the > point, surely. > >> == Re >> >> == Re arrays >> >>> Regarding arrays, have you considered allowing array-index writes if >> an hook is defined? i.e. "$x->foo['bar'] = 42;" could be treated >> as semantically equivalent to "$_temp =& $x->foo; $_temp['bar'] = 42; >> unset($_temp);" >> >> That's already discussed in the RFC: >> >>> The simplest approach would be to copy the array, modify it accordingly, >>> and pass it to set hook. This would have a large and obscure performance >>> penalty, and a set
Re: [PHP-DEV] [RFC[ Property accessor hooks, take 2
> On 28 Feb 2024, at 06:17, Larry Garfield wrote: > > On Sun, Feb 25, 2024, at 10:16 PM, Rowan Tommins [IMSoP] wrote: >> [Including my full previous reply, since the list and gmail currently >> aren't being friends. Apologies that this leads to rather a lot of >> reading in one go...] > > Eh, I'd prefer a few big emails that come in slowly to lots of little emails > that come in fast. :-) > >>> On 21/02/2024 18:55, Larry Garfield wrote: Hello again, fine Internalians. After much on-again/off-again work, Ilija and I are back with a more polished property access hooks/interface properties RFC. >>> >>> >>> Hello, and a huge thanks to both you and Ilija for the continued work >>> on this. I'd really like to see this feature make it into PHP, and >>> agree with a lot of the RFC. >>> >>> >>> My main concern is the proliferation of things that look the same but >>> act differently, and things that look different but act the same: > > *snip* > >>> - a and b are both what we might call "traditional" properties, and >>> equivalent to each other; a uses legacy syntax which we haven't >>> removed for some reason > > I don't know why we haven't removed `var` either. I can't recall the last > time I saw it in real code. But that's out of scope here. > > *snip* > >> I think there's some really great functionality in the RFC, and would >> love for it to succeed in some form, but I think it would benefit from >> removing some of the "magic". >> >> >> Regards, >> >> -- >> Rowan Tommins >> [IMSoP] > > > I'm going to try and respond to a couple of different points together here, > including from later in the thread, as it's just easier. > > == Re, design philosophy: > >> In C#, all "properties" are virtual - as soon as you have any >> non-default "get", "set" or "init" definition, it's up to you to declare >> a separate "field" to store the value in. Swift's "computed properties" >> are similar: if you have a custom getter or setter, there is no backing >> store; to add behaviour to a "stored property", you use the separate >> "property observer" hooks. >> >> Kotlin's approach is philosophically the opposite: there are no fields, >> only properties, but properties can access a hidden "backing field" via >> the special keyword "field". Importantly, omitting the setter doesn't >> make the property read-only, it implies set(value) { field = value } > > A little history here to help clarify how we ended up where we are: The > original RFC as we designed it modeled very closely on Swift, with 4 hooks. > Using get/set at all would create a virtual property and you were on your > own, while the beforeSet/afterSet hooks would not. We ran that design by > some PHP Foundation sponsors a year ago (I don't actually know who, Roman did > it for us), and the general feedback was "we like the idea, but woof this is > complicated with all these hooks and having to make my own backing property > for all these little things. Couldn't this be simplified?" We thought a bit > more, and I off-handedly suggested to Ilija "I mean, would it be possible to > just detect if a get/set hook is using a backing store and make it > automatically? Then we could get rid of the before/after hooks." He gave it > a quick try and found that was straightforward, so we pivoted to that > simplified version. We then realized that we had... mostly just recreated > Kotlin's design, so shrugged happily and went on with life. > > As noted in an earlier email, C#, Kotlin, and Swift all have different > stances on the variable name for the incoming value. We originally modeled > on Swift so had that model (optional newVal name), and also because we liked > how compact it was. When we switched to the simplified, incidentally > Kotlin-esque approach, we just kept the optional variable as it works. > > I think where that ended up is pretty nice, personally, even if it is not a > direct map of any particular other language. > > == Re asymmetric typing: > > This is capability already present today if using a setter method. > > class Person { >private $name; > >public function setName(UnicodeString|string $name) >{ >$this->name = $value instanceof UnicodeString ? $value : new > UnicodeString($value); >} > } > > And widening the parameter type in a child class is also entirely legal. As > the goal of the RFC is, essentially, "make most common getter/setter patterns > easy to add to a property without making an API-breaking method, so people > don't have to add redundant just-in-case getters and setters all the time," > covering an easy-to-cover use case seems like a good thing to do. > > It also ties into the question of the explict/implicit name, for the reason > you mentioned earlier (unspecified means mixed), not by intent. More on that > in another section. > > == Re virtual properties: > > Ilija and I talked this