Новое в PHP 8.4
PHP 8.4 убрал много шаблонного кода из классов: методы get и set во многих случаях больше не нужны. Появились и новые функции для массивов. Всё из этого урока требует версии 8.4 или новее.
Хук set
Хук — код, который выполняется при чтении или записи свойства. Хук set получает новое значение в переменной $value:
<?php
class User
{
public string $name {
set => trim($value);
}
public function __construct(string $name)
{
$this->name = $name;
}
}
$user = new User(' Анна ');
echo "[$user->name]"; // [Анна]Снаружи это обычное свойство, но в нём всегда лежит обрезанная строка. Раньше для этого писали закрытое свойство и метод setName().
Хук get
Свойство с одним хуком get не хранит значение — оно вычисляется при каждом обращении:
<?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Проверка в хуке
В полной записи хука — с фигурными скобками — можно проверить значение и отклонить его:
<?php
class Product
{
public int $price {
set {
if ($value < 0) {
throw new InvalidArgumentException('Цена не может быть отрицательной');
}
$this->price = $value;
}
}
}
$product = new Product();
$product->price = 250;
try {
$product->price = -5;
} catch (InvalidArgumentException $e) {
echo $e->getMessage(), ': ', $product->price;
}Программа выведет Цена не может быть отрицательной: 250 — неверное значение не записалось.
Раздельная видимость
Свойство можно сделать открытым для чтения и закрытым для записи:
<?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 'Изменить баланс снаружи нельзя';
}В отличие от readonly, такое свойство можно менять сколько угодно раз — но только изнутри класса.
Метод сразу после new
Раньше выражение new приходилось брать в скобки. Теперь метод вызывают сразу:
<?php
class Text
{
public function __construct(private string $value) {}
public function upper(): string
{
return mb_strtoupper($this->value);
}
}
echo new Text('привет')->upper(); // ПРИВЕТНовые функции для массивов
<?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) ? 'да' : 'нет', "\n"; // да
echo array_all($prices, fn($price) => $price > 100) ? 'да' : 'нет'; // нет| Функция | Что возвращает |
|---|---|
array_find() | Первый подходящий элемент или null |
array_find_key() | Ключ первого подходящего элемента |
array_any() | true, если подходит хотя бы один |
array_all() | true, если подходят все |
Ещё в 8.4 появились mb_trim(), mb_ucfirst() и атрибут #[\Deprecated], которым помечают устаревшие функции.
Частая ошибка
Свойство с одним хуком get — вычисляемое, записать в него нельзя:
<?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 'Площадь вычисляется, присвоить её нельзя';
}Чтобы изменить площадь, меняют ширину или высоту. И помните о версии: на сервере с PHP 8.3 файл с хуками не запустится вовсе — проверьте php -v.