4 ms·
I'm most excited for property hooks. Having getters and setters as part of the language syntax was something I dearly missed from my C# days, nearly two decades
by acabal 2y ago
I'm most excited for property hooks. Having getters and setters as part of the language syntax was something I dearly missed from my C# days, nearly two decades ago.
In my projects I sometimes emulate getters and setters using `__get()` and `__set()` but that's heavy-handed and requires lots of PHPDoc annotation for type checking. Property hooks look awesome!
- Xeoncross 2y agoI'm curious, why do you like getters and setters? I know the textbook answer is so that every single possible property can become some mutable chain of events so you can swap names or side-effects without the caller knowing, but I've yet to find a use for that in real life. It just leads to builder patterns and other oddities like forced decorators like Java has everywhere. I felt like beans were the realization that perhaps we shouldn't be doing this.
- munk-a 2y agoI've always been a fan because if a property turns from a simple value to a more complex interaction that might involve DB operations or other side effects then if a getter is in place you can modify the logic without needing to update widespread code.
- hamandcheese 2y agoIf you are replacing a performant property with a slow network call, you are being negligent if you aren't reviewing all the callers to make sure that is okay.
- hparadiz 2y agoIn a typical ORM when you do say $Model->DateTime = 1732046457; the __set is actually checking the value and seeing oh it's an integer. Treat this as a unix timestamp. But when you run save() the query is actually converting that to a Y-m-d H:i:s (for MySQL/MariaDB). This doesn't actually happen until you run save() when it makes the query and runs the network call. Most of that time it's actually storing everything in memory. But you might want to support string date times and the PHP object DateTime as well. So a typical well designed ORM converts multiple PHP types into a SQL string for saving. That's what the historical __set and __get are all about. This is called "mapping" by most ORMs and a very well designed modern one like Doctrine will actually have mappings for different SQL storage engines available. Obviously it also has to handle the reverse.
- hamandcheese 2y agoThat is a fine argument for setters, but I still don't see the connection between that, and the desire to disguise properties as setter methods.
- hparadiz 2y agoSome light weight ORMs do not require you to define all the properties ahead of time. They pull the field names from the table and generate the model record on the fly for you. This generally lets you prototype really fast. Laravel's Eloquent is known to do this. It's also useful for derived SQL fields when you use custom queries or join from other tables. Also kinda fun to do it for properties backed by a method. As in $record->isDirty will run isDirty() under the hood for you. All these things can be documented with PHPDoc and static analyzers handle it just fine.
- hamandcheese 2y agoIs it possible to dynamically define methods in PHP?
- hparadiz 2y agoYes.
- wvenable 2y agoA method is supposed to be an action and a property is supposed to be data. So I don't see the desire to disguise setting data as a "setting method" rather than using the syntax of assignment.
- hamandcheese 2y ago> A method is supposed to be an action and a property is supposed to be data. I agree! That's why it's wild to allow a setter to do literally anything. You aren't just setting a property, there is a conversion happening under the hood. And the reason I hate it is that code that appears to be infallible, isn't. It can have arbitrary side effects, raise exceptions, have unbounded runtime, etc.
- acabal 2y agoThey are very useful when modeling CRUD-dy objects, because you can lazy-load infrequently-accessed child object using getters. It makes for a cleaner OOP-y interface in which the caller only cares about actually exposed properties and not methods to get and manipulate hidden properties. IMHO using properties directly is a much more natural way to talk about objects, than having a bunch of methods to get properties. Getters and setters also help ensure that methods are only for changing an object's state, not getting an object's state. For example: class User{ public ForumsPost $LastForumsPost{ get{ if(!isset($this->LastForumsPost)){ $this->LastForumsPost = <get from database...>; } // Return the cached property so we don't keep hitting the database. return $this->LastForumsPost; } } } print($user->LastForumsPost->Title); print($user->LastForumsPost->PostId); // instead of... print(($user->GetLastForumsPost())->Title); print(($user->GetLastForumsPost())->PostId);
- hamandcheese 2y agoI do not see any advantage here. All I see (or rather, what can't be seen) is hidden control flow. For what? To save a few characters?
- acabal 2y agoIt's a matter of OOP modeling. Object methods are better reserved for performing actions with side effects, or complex logic or calculations, and not for getting state or simply setting public properties; and as a caller, I don't really care about the implementation details of (in my above example) getting the last forums post, I just care that it's a property I can access. (Maybe it came from a cache and not the database? Maybe it was set earlier in the script? I don't care.) Putting it behind a getter doesn't "hide" control flow. It just makes for a cleaner interface from the caller's perspective. FWIW, I almost never use setters. Getters are are much more useful, especially for lazy-loading basic properties.
- Xeoncross 2y agoI appreciate the detailed answer, thanks. However, It feels like $a->foo vs $a->foo() is a personal preference that hides the fact you're doing work behind the scenes. Then again, I'm not a fan of code that does magical things that aren't apparent. Makes it a lot harder to 1) reason about and 2) solve performance issues. I also don't want the overhead of function lookups for every property access.
- dragontamer 2y agoThe more I program the more I realize that we are all blind men feeling out an elephant. It sounds like you got the gist but somehow you are in an area of programming where getter/setters aren't useful. That's fine and okay. Part of growing up as a programmer is realizing your niche. Most of the advice out there is deep, not broad. It's deeply connected with our niche and not necessarily broadly applicable.
- smt88 2y agoThis was weirdly condescending and content-free. I've been programming for 30 years, and getters/setters are both pointless and anti-productive. They hide (potentially a lot of) code from people reading the program, which leads to a lot of "wtf" moments later. Magic in general is bad, and it's the kind of "look how concise and clever I am" thinking that leads to unmaintainable software. If setting a property isn't straightforward, make it private/protected and add explicit getter/setter methods. It's more work today and much less work later on.
- hparadiz 2y agoEvery php ORM disagrees. Nothing about it is magic
- smt88 2y agoPHP ORMs and ORMs in general are notoriously hard to maintain. I've written hundreds of thousands of lines of PHP, I'm speaking from experience.
- hparadiz 2y agoI maintain an ORM [ https://github.com/Divergence/framework/blob/release/src/Models/ActiveRecord.php https://github.com/Divergence/framework/blob/release/src/Mod... ] and have also maintained a job's fully custom ORM as well. 20 YOE in PHP. Also speaking from experience :)
- keybored 2y ago
- hparadiz 2y agoThey are used in ORMs to do property value conversions from PHP primitives to values a data store might actually want. I wrote about it here https://technex.us/2023/07/php-attributes-are-so-awesome-i-just-had-to-add-attribute-based-field-mapping-to-my-orm/ https://technex.us/2023/07/php-attributes-are-so-awesome-i-j...
- whalesalad 2y agoGetters are great for manipulating data on the way out. For instance, inside the class you might store a raw representation of the data like a json string, but when reading an attribute you will decode that json string into a datastructure and pluck a certain item. I use dynamic getters often to wrap a raw value with some kind of fallback: do this if no data is present, do this if the data is present but is ancient (ie a seamless upgrade of a v1 internal datastructure to a v2 output), etc. For setters, I try not to have implicit side effects but in certain cases where it makes sense, it is nice to be able to centralize that logic: "if this value changes, ensure x and y occur" which you get "for free throughout your codebase when you use a setter, versus having to go thru the entire codebase and sprinkle the do_x() and do_y() calls (which then becomes additional footprint to maintain and worry about)
- foolfoolz 2y agothis was the one feature i read in here thinking “why would anyone want this?” seemed like a way to backport poor librar/framework choices to have IDE support but not for new code
- munk-a 2y agoI've written some auto-getter and setter spawners and with reflection it's pretty do-able to implement proper type checking as long as the type you want to check for matches the type declared on the property. PHP meta-coding is actually quite advanced and pretty accessible compared to what I've done in other languages.