Developers often use methods to wrap and guard access to object properties. There are several highly common patterns for such logic, which in practice may be verbose to implement repeatedly. Alternatively, developers may use __get
and __set
to intercept reads and writes generically, but that is a sledge-hammer approach that intercepts all undefined (and some defined) properties unconditionally. Property hooks provide a more targeted, purpose-built tool for common property interactions.
class User { public string $name { set { if (strlen($value) === 0) { throw new ValueError("Name must be non-empty"); } $this->name = $value; } } public function __construct(string $name) { $this->name = $name; } }
You can play around with them on 3v4l.org
i think it went too far with the virtuals
<?php class User { public string $name = 'default' { set { if (strlen($value) === 0) { throw new ValueError("Name must be non-empty"); } $field = ucfirst($value); } get { notifyMutationObserver(); return $this->name; } } public string $badIdeaNoSetterVirdualProp { get { return $this->name; } // set ERROR! I don't like this idea... } public readonly array $lazy { get { return $this->lazy = getBigData(); } // set NO! see declaration, its readonly } public function __construct(string $name) { $this->name = $name; unset($this->lazy); } } $u = new User('roman'); var_dump($u->name);
I prefer the addition of these types of features to the language. Small changes, which in principle will only be used for very specific cases. But in the end they serve to reduce hundreds of lines of superfluous code and make the code easier to read.
Any boilerplate that can go should go
Is a type of writing properties that has also established itself very well in other languages, I would love to see this also in PHP
Simple validation in most cases should be done by passing value object, which already is in valid state.
it is easy to manupulate
i like this just for cutting down the abuse of magic methods. Likewise, if you opt for concrete get/set methods, you add irritating boilerplate, and clutter up functionality. The interface has to be concerned with implementation (i.e. knowing what properties are expected), or API documentation has to be coupled with specific implementation.
i see the constructive points being made against this (more than just "ew it looks like C#"), but i think this feature can coexist with other patterns. There's no magic bullet design pattern, so it's naive to say pattern A always is better than B so B shouldn't exist.
i'm on board with those who dislike the magic variables. Replacing magic __get()
/__set()
with magic variables is nauseating.
i think this RFC needs to require arrow-functions v2 before it gets reconsidered. Then the hooks can use that syntax with more concrete code:
class Foo { public string $bar { get: ($field) => { // do multi-line stuff }, set: (&$field, $value) => { // do multi-line stuff } }; }
$field
is defined and passed with the concrete property's value. For get
it's a pass-by-value to avoid magic writes back to the property, and in set
it's a reference to confer the new value back to the property. The syntax is required, but you can name the variables whatever makes sense to you (same as you can do with magic method parameters).
This is good to have
i don't see any use case that can not be solved better with a value object.
i rather validate the whole object than properties by itself.
I want it!
good
Even though this is a nice syntax that we also know from other programming languages, I think it is problematic. The reason for this lies in the ambiguity: How does the developer know whether $entity->setSlug() = '...'
does something different than $entity->slug
?
Without property hooks the case is quite clear: the setter method could still contain some "under-the-hood" steps (such as validation), while directly changing the property sets the value "unfiltered". It should stay that way.
I like the idea - getting away from the mess that __get
and __set
can introduce is a great goal, but this example is confusing and appears to be incomplete. I checked the RFC for more details, and the number of different forms this could take just made me even more confused. Why do we need multiple variants and combinations of shorthand and magic variables, when it's ultimately just defining a special use case function? I'd be much happier with a simple keyword added to a normal function definition to denote it's purpose.
Interface Default Methods improves backwards compatibility when changing interfaces, but also add a way to have multi-inheritance in PHP.
A new syntax for declaring the “set” operation visibility of an object property
Chain method on newly created objects without parentheses