4 ms·
I was curious about why setting `$this->countryCode` inside the setter for `countryCode` didn't result in infinite recursion. Turns out this is spelled out in t
by eurleif 2y ago
I was curious about why setting `$this->countryCode` inside the setter for `countryCode` didn't result in infinite recursion. Turns out this is spelled out in the RFC, but not in the docs:
When a hook is called, inside that hook $this->[propertyName] will refer to the “unfiltered” value of the property, called the “backing value.” When accessed from anywhere else, $this->[propertyName] calls will go through the relevant hook. This is true for all hooks on the same property. This includes, for example, writing to a property from the get hook; that will write to the backing value, bypassing the set hook.
A normal property has a stored “backing value” that is part of the object, and part of the memory layout of the class. However, if a property has at least one hook, and none of them make use of $this->[propertyName], then no backing value will be created and there will be no data stored in the object automatically (just as if there were no property, just methods). Such properties are known as “virtual properties,” as they have no materialized stored value.
Be aware, the detection logic works on $this->[propertyName] directly at compile time, not on dynamic forms of it like $prop = 'beep'; $this->$prop. That will not trigger a backing value.
Feels like too much magic to me that a property access can mean different things depending on context, but I'm not a PHP user, so I don't get a vote.
- tail_exchange 2y agoI'm also not a php developer, but I agree. This seems like a huge footgun. I've never been a fan of this kind of magic, and I wonder how other languages deal with this case.
- crimsonnoodle58 2y agoWell in python I assume it would be equivalent of accessing: self.__dict__['property_name'] And if those PHP rules were in python you could just write: @property def property_name(self): return self.property_name In actual python though, that would infinitely recurse.
- arkh 2y agoOr if they could follow Godot syntax: https://docs.godotengine.org/en/stable/tutorials/scripting/gdscript/gdscript_basics.html#properties-setters-and-getters https://docs.godotengine.org/en/stable/tutorials/scripting/g... var milliseconds: int = 0 var seconds: int: get: return milliseconds / 1000 set(value): milliseconds = value * 1000
- kijin 2y agoIt might be a footgun, but it will be extremely obvious when it is triggered.
- Liquidor 2y agoLua has rawget() and rawset() to bypass the magic methods, which is used a lot inside/outside the metatables (objects with magic methods) to avoid magic loops I guess.
- Drew_ 2y agoC# has the same thing as Properties, but the backing value is set explicitly as a separate variable: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/using-properties https://learn.microsoft.com/en-us/dotnet/csharp/programming-...
- wvenable 2y agoThere are many times I would love to have an automatic backing field in C#. C# will do that if you use the default setter but in cases where that's not possible I dislike having to both declare a separate field and having it available to the rest of the class outside of the setter.
- neonsunset 2y agohttps://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-13#the-field-keyword https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/cs... edit: the properties reference now documents the 'field' keyword too
- wvenable 2y agoThat might be all the motivation I need to go move to .NET 9.
- runevault 2y ago.NET 9 has so much good stuff in it. Thing that I randomly realized I wanted only to find out it works in 9 is dictionary access with "related" types (so like if you have a ReadOnlySpan<char> you can use that to find a value from a string in the dictionary via a value type created off the dict).
- bwoebi 2y agoC# 13 has this via the field keyword (as preview feature): https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/field https://learn.microsoft.com/en-us/dotnet/csharp/language-ref... It's pretty similar to what PHP provides here, except that PHP uses "$this->propname =" and C# uses "field =". Edit: As someone involved in the RFC, it's somewhat funny, because we considered a special variable like "$field" or "$value" too magic, and C# does just that with a field keyword.
- nedt 2y agoThe dynamic form is really not needed very often. Should it ever become a problem triggering a loop you can just set and get from a private property with a different name. But then also 90% of getters and setters are really simple so it will feel as magic as gravity.
- akie 2y agoWhenever I read about a new PHP release on HackerNews I always come away disappointed with the discussion. You are right, the "magic" that the top comment is complaining about is a non-issue, and I say that as someone who really strongly dislikes "magic" behavior. In fact, you can imagine what their argument WOULD have been if setting `$this->countryCode` inside the setter for `countryCode` DID result in infinite recursion. When it comes to PHP, whatever it does, on HackerNews and in the rest of the industry, it just results in a bunch of people complaining about it. Disappointing, and unprofessional.
- ezekiel68 2y agoFunny world where a feature to prevent infinite recursion -- at a moment in the runtime lifecycle where that would make sense -- is somehow viewed as dangerous footgun magic (addresed to: several replies under this comment).
- Dylan16807 2y agoYou could prevent the recursion without this magic, by making the access a compiler error.
- Implicated 2y ago404 ComPHPiler Not Found
- Dylan16807 2y agoWhatever you want to call the code that parses the file and emits a syntax error. Though what would you personally call "the thing that turns it into bytecode"?
- stephenr 2y agoThe original RFC that led to this feature originally used a special variable to indicate the backing store; that was overwhelmingly disliked, as it was "magic". Conversely php already has other places where context affects property accesses, and IME it's not the problem you make it out to be.
- hipadev23 2y ago> too much magic The backing value is effectively private to everything but its own get/set methods, that seems fairly straightforward to me.
- eurleif 2y agoWhat's magic is that `$this->foo` refers to different entities in different contexts despite the same value of `$this`, not that one of the entities to which it refers can be private.