Магические методы
Магические методы PHP вызывает сам — в особых ситуациях: при превращении объекта в строку, при обращении к несуществующему свойству, при копировании. Их имена начинаются с двух подчёркиваний. С одним из них вы уже знакомы — это конструктор __construct().
__toString
Метод __toString() определяет, как объект превращается в строку:
<?php
class Money
{
public function __construct(private int $amount, private string $currency) {}
public function __toString(): string
{
return $this->amount . ' ' . $this->currency;
}
}
echo new Money(250, 'RUB'); // 250 RUBБез этого метода попытка вывести объект через echo завершилась бы ошибкой.
__get и __set
__get() вызывается при чтении свойства, которого нет или к которому нет доступа, __set() — при записи:
<?php
class Settings
{
private array $data = [];
public function __get(string $name)
{
return $this->data[$name] ?? null;
}
public function __set(string $name, $value): void
{
$this->data[$name] = $value;
}
}
$settings = new Settings();
$settings->theme = 'dark';
echo $settings->theme; // darkСнаружи это выглядит как обычные свойства, а внутри значения лежат в массиве.
__isset
Чтобы для таких свойств работали isset() и оператор ??, добавляют __isset():
<?php
class Settings
{
private array $data = ['theme' => 'dark'];
public function __isset(string $name): bool
{
return isset($this->data[$name]);
}
}
$settings = new Settings();
var_dump(isset($settings->theme)); // bool(true)
var_dump(isset($settings->size)); // bool(false)__call
__call() перехватывает вызов несуществующего метода. Он получает имя метода и массив аргументов:
<?php
class Logger
{
public function __call(string $level, array $arguments): string
{
return strtoupper($level) . ': ' . $arguments[0];
}
}
$logger = new Logger();
echo $logger->info('Запуск'), "\n"; // INFO: Запуск
echo $logger->error('Сбой'); // ERROR: СбойМетодов info() и error() в классе нет — оба вызова обработал __call().
__invoke
С методом __invoke() объект можно вызывать как функцию:
<?php
class Multiplier
{
public function __construct(private int $factor) {}
public function __invoke(int $number): int
{
return $number * $this->factor;
}
}
$triple = new Multiplier(3);
echo $triple(5), "\n"; // 15
echo implode(', ', array_map($triple, [1, 2, 3])); // 3, 6, 9Такой объект подходит везде, где ожидают callable.
Клонирование
Оператор clone создаёт копию объекта. Метод __clone() вызывается у копии — в нём копируют вложенные объекты, иначе они останутся общими:
<?php
class Order
{
public DateTime $createdAt;
public function __construct()
{
$this->createdAt = new DateTime('2025-01-30');
}
public function __clone()
{
$this->createdAt = clone $this->createdAt;
}
}
$first = new Order();
$second = clone $first;
$second->createdAt->modify('+1 day');
echo $first->createdAt->format('d.m'), ' ', $second->createdAt->format('d.m'); // 30.01 31.01Частая ошибка
__get() и __call() прячут от редактора и от читателя, какие свойства и методы есть у класса: опечатка в имени не даст ошибки, а вернёт null. Используйте их только там, где список имён действительно неизвестен заранее. В остальных случаях объявляйте свойства и методы явно.