PHP 8.4 shipped a new feature called “Property Hooks”. To find out what they are, check out the documentation at https://www.php.net/manual/en/language.oop5.property-hooks.php or read about their origin story from Larry Garfield on the PHP Foundation blog https://thephp.foundation/blog/2024/11/01/how-hooks-happened/
A discussion of this feature on Mastodon prompted me to write down my thoughts on why I am a proponent of this feature and think it’s a great addition to the PHP language.
To me the useful part of Property Hooks is their existence but the less often they are used the better. They are a kind of insurance for cases of otherwise catastrophic future change, that you hopefully never need, but that gives you peace of mind.
Historical/Theoretical problematic public property use
Using plain public properties you could define a class Foo as follows and its property $name may be used in various places directly.
class Foo
{
public string $name;
}
// OtherFile.php
$foo->name = 'Jane';
// AnotherFile.php
$output = 'Hello '.$foo->name;
If you now urgently need to change that names are always used in all caps everywhere in your application, it means that you have to touch every file that reads $foo->name or writes $foo->name or even both depending on how you want to store the data internally.
In reality this scenario also happens very rarely. You can tell from this contrived example, how likely is it that an application suddenly needs its name in all caps everywhere. More likely you’d want it in all caps in some places and you could just add a function to get the name in all caps for those places.
But if one needs to make this kind of a change to all calling sites of a property it would be an extremely error prone process and a fair bit of effort since a large codebase could have thousands of calling sites for the property.
State of the art today
So to combat this potential problem, in PHP today we often see classes defined with plain getters and setters that simply wrap access to a private or protected property, so that you must use the functions to modify or retrieve the property’s state. That means in the event described above, that you must make a change to all places reading or writing the property, you can simply modify the code in either of these two functions instead of thousands of calling sites.
class Foo
{
private string $name;
public function getName(): string
{
return $this->name;
}
public function setName(string $value): void
{
$this->name = $value;
}
}
// OtherFile.php
$foo->setName('Jane');
// AnotherFile.php
$output = 'Hello '.$foo->getName();
You can see that the getter and setters take up 8 non-empty lines here. All they accomplish is assigning and getting the value of the private property $name. One could instead declare the property $name public, but then you’d risk having to touch every place that access this code in the unlikely scenario that you want to generally change how names are read from our Foo class.
Property Hooks as insurance: Use public properties without fear
Now with the introduction of property hooks, we can delete those 8 lines of boilerplate code and return to our basic class definition from above.
class Foo
{
public string $name;
}
// OtherFile.php
$foo->name = 'Jane';
// AnotherFile.php
$output = 'Hello '.$foo->name;
But the existence of property hooks lets us write this code without a bad feeling in the back of our head about that potential future event that will force us to touch thousands of places in our code base that access the name property. If that day ever comes, we could use a property hook to change read behavior without touching any calling sites.
class Foo
{
public string $name {
get => strtoupper($this->name);
}
}
// OtherFile.php
$foo->name = 'Jane';
// AnotherFile.php
$output = 'Hello '.$foo->name;
But hopefully these events are just as exceedingly rare as it is uncommon today for anyone to actually modify a getter or setter to do anything other than the default read/write behavior.
I hope to see as little use of property hooks as possible in PHP applications. I support the creation of policies advocating against the use of property hooks unless absolutely unavoidable. If you plan on implementing more complex behavior to set or retrieve a value from the start, just define functions as you would today and use a private property.
And yet I applaud the addition of Property Hooks to PHP, that I’ve long waited for. I thank everyone involved in proposing and implementing this feature, simply because finally we can delete all these unnecessary boilerplate getter and setter functions. Because finally we feel safe to do so, cause Property Hooks serve as our insurance for potential future costs of change.