Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

New in PHP 8.4

PHP 8.4 removed a lot of boilerplate from classes: get and set methods are often no longer needed. New array functions appeared too. Everything in this lesson requires version 8.4 or newer.

The set hook

A hook is code that runs when a property is read or written. The set hook receives the new value in the $value variable:

<?php
 
class User
{
    public string $name {
        set => trim($value);
    }
 
    public function __construct(string $name)
    {
        $this->name = $name;
    }
}
 
$user = new User('  Anna ');
 
echo "[$user->name]"; // [Anna]

From outside it is an ordinary property, yet it always holds a trimmed string. Previously this took a private property and a setName() method.

The get hook

A property with only a get hook stores no value — it is computed on every access:

<?php
 
class Rectangle
{
    public int $area {
        get => $this->width * $this->height;
    }
 
    public function __construct(public int $width, public int $height) {}
}
 
$box = new Rectangle(3, 4);
 
echo $box->area; // 12

Validating in a hook

The full form of a hook — with curly braces — can check a value and reject it:

<?php
 
class Product
{
    public int $price {
        set {
            if ($value < 0) {
                throw new InvalidArgumentException('The price cannot be negative');
            }
 
            $this->price = $value;
        }
    }
}
 
$product = new Product();
$product->price = 250;
 
try {
    $product->price = -5;
} catch (InvalidArgumentException $e) {
    echo $e->getMessage(), ': ', $product->price;
}

The program prints The price cannot be negative: 250 — the wrong value was not written.

Asymmetric visibility

A property can be public for reading and private for writing:

<?php
 
class Account
{
    public private(set) int $balance = 0;
 
    public function deposit(int $amount): void
    {
        $this->balance += $amount;
    }
}
 
$account = new Account();
$account->deposit(500);
 
echo $account->balance, "\n"; // 500
 
try {
    $account->balance = 1000000;
} catch (Error $e) {
    echo 'The balance cannot be changed from outside';
}

Unlike readonly, such a property can change any number of times — but only from inside the class.

A method right after new

A new expression used to need parentheses. Now a method is called at once:

<?php
 
class Text
{
    public function __construct(private string $value) {}
 
    public function upper(): string
    {
        return strtoupper($this->value);
    }
}
 
echo new Text('hello')->upper(); // HELLO

New array functions

<?php
 
$prices = [120, 450, 90, 700];
 
echo array_find($prices, fn($price) => $price > 400), "\n";     // 450
echo array_find_key($prices, fn($price) => $price > 400), "\n"; // 1
echo array_any($prices, fn($price) => $price > 600) ? 'yes' : 'no', "\n"; // yes
echo array_all($prices, fn($price) => $price > 100) ? 'yes' : 'no';       // no
FunctionWhat it returns
array_find()The first matching element or null
array_find_key()The key of the first matching element
array_any()true if at least one matches
array_all()true if all match

8.4 also added mb_trim(), mb_ucfirst() and the #[\Deprecated] attribute for marking outdated functions.

Common mistake

A property with only a get hook is computed and cannot be written:

<?php
 
class Rectangle
{
    public int $area {
        get => $this->width * $this->height;
    }
 
    public function __construct(public int $width, public int $height) {}
}
 
$box = new Rectangle(3, 4);
 
try {
    $box->area = 100;
} catch (Error $e) {
    echo 'The area is computed and cannot be assigned';
}

To change the area, change the width or the height. And mind the version: on a server with PHP 8.3 a file with hooks does not run at all — check php -v.

Thanks for reading!

Donate to the site — we work hard for you.