DEV Community

Cover image for PHP Snippets: Property Hooks
Travis van der F.
Travis van der F.

Posted on

PHP Snippets: Property Hooks

PHP 8.4 just made our lives easier. Remember all those getter and setter methods we wrote? There's a better way now!

The Modern Method

Property hooks allow attaching logic directly to properties:

class Berry
{
    public string $name {
        get => ucfirst($this->value);
        set => trim($value);
    }
}

$berry = new Berry();
$berry->name = "  strawberry  ";
echo $berry->name; // Strawberry
Enter fullscreen mode Exit fullscreen mode

And really, that's it!

No separate methods needed. The get hook capitalizes the first letter when reading the property, and the set hook trims whitespace when writing to it. Clean, readable, and everything's in one place.

Reviewing the Legacy Method

Because it's good to know the fundamentals and history, before PHP 8.5, we had to write this whole dance:

class Berry
{
    private string $name;

    public function getName(): string
    {
        return ucfirst($this->name);
    }

    public function setName(string $value): void
    {
        $this->name = trim($value);
    }
}

$berry = new Berry();
$berry->setName("  blueberry  ");
echo $berry->getName(); // Blueberry
Enter fullscreen mode Exit fullscreen mode

It's the same result, but with much more code. A private property was required, along with getter and setter methods. It all added up quickly, especially with multiple properties.

Overall, property hooks aren't just about saving keystrokes. They make code easier to understand because the logic lives right where the property is defined. No hunting through classes to find where values get transformed, adding extra text for the eyes. It's all there, front and center.

Welcome to modern PHP!
#HappyCoding

Top comments (3)

Collapse
 
xwero profile image
david duymelinck • Edited

From the start you made the mistake that property hooks are a PHP 8.5 feature, it is a PHP 8.4 feature.

The main problem with public properties was that you needed the __get and __set methods to add extra logic. The more properties that exist the larger the methods got.
The other negative consequence was that the property could only be defined in the magic methods, which is a problem for the compiler cache to figure out the hot paths in the code.

It is less about saving keystrokes or making the code easier to understand, because you could already write

class Berry
{
    public string $name;

    public function __construct(string $name)
    {
        $this->name = ucfirst(trim($name));
    }
}

$a = new Berry('  strawberry   ');

echo $a->name; // Strawberry
Enter fullscreen mode Exit fullscreen mode

The problem with this code is that it is possible to set the name property after instantiation, and it will not use the formatting functions.
A way to go is to make it private, but that also means the property need a getter function.
PHP 8.4 also introduced asymmetric visibility, which means with one change it is not needed to make the property private.

class Berry
{
    public private(set) string $name; // change

    public function __construct(string $name)
    {
        $this->name = ucfirst(trim($name));
    }
}

$a = new Berry('  strawberry   ');

echo $a->name;

$a->name = 'blueberry' // throws an exception
Enter fullscreen mode Exit fullscreen mode

The modern way to handle class properties is:

  • Make the properties readonly when they should not be manipulated.
  • Use asymmetric visibility when they need initial manipulation.
  • Use property hooks when they will be manipulated after class instantiation.
Collapse
 
travisfont profile image
Travis van der F.

Thanks for the version correction; it was an error!

Your second code example is nice, but it is a slightly different pattern (using the constructor instead for a one-time assignment). The class behaves as an immutable object.

That said, it gives me an idea for another code snippet article on native DTO-like patterns. Appreciate the inspiration :]

Collapse
 
xwero profile image
david duymelinck

You are right that my example is a different way to set the properties.
The reason I showed it is that people shouldn't go from getter/setter methods to property hooks all the time. It depends on the functionality of the object.
I think you should start with a immutable mindset, and only when immutability has the code jumping trough too many hoops mutations should be on the table.

It is good the property hooks feature exists, but it should be used in the right context.