PHP 8.4 was released in November 2024 and is one of the most noticeable updates in years. It brings property hooks, separate read and write visibility for properties, new array functions and a DOM API that parses HTML5 properly. Here is a practical walkthrough, followed by what to check before switching a hosted site to 8.4.
Property hooks: validation without getters and setters
Validating a value on write used to mean a private property plus getName() and setName() methods, which produced a lot of boilerplate. In PHP 8.4 the logic attaches directly to the property. Outside code still reads and writes a plain property, but your code runs on every access. Consider a product class for a small Tashkent online shop:
class Product
{
public string $name {
set(string $value) {
$this->name = trim($value);
}
}
public int $price {
set(int $value) {
if ($value < 0) {
throw new InvalidArgumentException('Price cannot be negative');
}
$this->price = $value;
}
}
// Virtual property: read-only, not stored
public string $fullName {
get => $this->name . ' - ' . number_format($this->price) . ' UZS';
}
}
$p = new Product();
$p->name = ' Teapot ';
$p->price = 85000;
echo $p->fullName; // Teapot - 85,000 UZS
$fullName is virtual: nothing is stored and the value is computed on each read. Hooks can also be declared in interfaces, so an interface can now require properties, not just methods.
Asymmetric visibility
Often a property should be readable by everyone but writable only by the class itself, such as an order status that changes only through a method:
class Order
{
public private(set) string $status = 'new';
public function pay(): void
{
$this->status = 'paid';
}
}
$o = new Order();
$o->pay();
echo $o->status; // paid
$o->status = 'cancelled'; // Error: cannot modify from outside
protected(set) also allows child classes to write.
New array functions and smaller conveniences
array_find(), array_find_key(), array_any() and array_all() replace many foreach loops. In a clinic booking system you can write array_find($appointments, fn($a) => !$a['confirmed']) to get the first unconfirmed appointment, or array_all($appointments, fn($a) => $a['confirmed']) to check whether everything is confirmed.
You can now chain on new without wrapping parentheses: new DateTimeImmutable()->format('Y-m-d'). Multibyte-safe mb_trim(), mb_ltrim(), mb_rtrim(), mb_ucfirst() and mb_lcfirst() help with Cyrillic and Uzbek text. The #[\Deprecated] attribute lets you mark your own functions as deprecated. The new Dom\HTMLDocument class parses HTML5 like a browser and supports CSS selectors, and lazy objects, aimed mainly at frameworks, delay object creation until first use.
Deprecations and removed extensions
- Implicitly nullable parameters such as
function save(Product $p = null)are deprecated; write?Product $p = null. Older plugins contain many of these, so expect more Deprecated notices in logs. - IMAP, OCI8, PDO_OCI and pspell moved out of core into PECL. If your site reads a mailbox with
imap_*functions, check this first. - The default bcrypt cost in
password_hash()rose from 10 to 12. - The
E_STRICTconstant is deprecated.
Moving a hosted site to 8.4
For an existing site the main gains are speed and a longer security support window. Confirm that your CMS, theme and plugins support 8.4, back up files and the database, and test on a copy if possible. On sayt.uz hosting the PHP version is selected per site in ISPmanager, so switching one site does not affect the others. Watch the error log for a couple of days afterwards. A Fatal error means switching back and fixing the code calmly; Deprecated notices alone do not stop the site, but they may become errors in future versions.