Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Магические методы

Магические методы 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. Используйте их только там, где список имён действительно неизвестен заранее. В остальных случаях объявляйте свойства и методы явно.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.