Property Hooks

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

Click the bar to cast your vote!
61%
39%
1

I do believe this has merit and uses cases, but I agree that value objects would cover this better and there are other things the developers could put their time towards

Share:
nathan avatar
nathan
voted no
1

This RFC needs a re-work. While I support the idea, I don't think this is the right approach. The fact that the RFC is so long is a massive red flag. For example there are 4 different ways to define hooks:

class User
{
    public string $username {
        set(string $value) {
            $this->username = strtolower($value);
        }
    }
}
class User
{
    public string $username {
        set(string $value) {
            $field = strtolower($value);
        }
    }
}
class User
{
    public string $username {
        set => strtolower($value);
    }
}
class User
{
    public function __construct(
        public string $username { set => strtolower($value); }
    ) {}
}

Why?!

This is not what PHP needs.

Share:
moebrowne avatar
moebrowne
voted no
1

I enjoy using set/get hooks in C# and strongly believe they are truly useful. Also, having them in interfaces is excellent!

Share:
baldie avatar
baldie
voted yes
1

Even if you won't use this yourselve, it will allow libraries and frameworks to do some really cool stuff. LGTM!

Share:
sandermuller avatar
sandermuller
voted yes
1

I've always envied C# developers for this feature in C#, I've been using __get() and __set() methods to achieve it

Share:
hsemix avatar
hsemix
voted yes
1

It's hard to read.

Share:
bYemma avatar
bYemma
voted no
1

This RFC does not solve any issue, that cannot be solved right now with almost the same code, and makes the code harder to read. Beside this, this syntax invites developers to mix concerns.

Share:
im-a-teapot avatar
im-a-teapot
voted no
1

Getters and setters are more and more considered bad : https://www.infoworld.com/article/2073723/why-getter-and-setter-methods-are-evil.html

This features feels like a C# fix applied on PHP which I don't like. We should focus on designing better classes, not fix a bad pattern.

Share:
trehinos avatar
trehinos
voted no
1

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);
Share:
yarns avatar
yarns
voted no
1

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.

Share:
mmarquez avatar
mmarquez
voted yes
1

Any boilerplate that can go should go

Share:
richard4339 avatar
richard4339
voted yes
1

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

Share:
ddegasperi avatar
ddegasperi
voted yes
1

Simple validation in most cases should be done by passing value object, which already is in valid state.

Share:
lkankowski avatar
lkankowski
voted no
1

it is easy to manupulate

Share:
paramientos avatar
paramientos
voted yes
1

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).

Share:
thookerov avatar
thookerov
voted yes

Check out another RFCs

The Pipe Operator

The "pipe operator" |> allows you to chain multiple function calls in a more convenient way.

90
262 yes
122 no
new MyClass()->method() without parentheses

Chain method on newly created objects without parentheses

29
38 yes
13 no
Interface Default Methods

Interface Default Methods improves backwards compatibility when changing interfaces, but also add a way to have multi-inheritance in PHP.

95
168 yes
263 no
RSS Feed Contribute Watch on YouTube Our License
© 2024 RFC Vote. This project is open source. Contribute and collaborate with us!