OOP: магические методы
Glossary overview

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

Магические методы — это специальные методы которые PHP вызывает автоматически в определённых ситуациях. Начинаются с двойного подчёркивания __.

Шпаргалка

МетодКогда вызывается
__constructпри new
__destructпри уничтожении объекта
__getчтение несуществующего свойства
__setзапись несуществующего свойства
__issetisset() на несуществующем свойстве
__unsetunset() на несуществующем свойстве
__callвызов несуществующего метода
__callStaticвызов несуществующего статического метода
__toStringобъект используется как строка
__invokeобъект используется как функция (используется часто в laravel в однометодных контроллерах)
__cloneпри clone
__sleepпри serialize()
__wakeupпри unserialize()
__debugInfoпри var_dump()

__construct и __destruct

class Database
{
    public function __construct()
    {
        echo "Соединение открыто" . PHP_EOL;
        // вызывается при создании объекта
    }

    public function __destruct()
    {
        echo "Соединение закрыто" . PHP_EOL;
        // вызывается когда объект уничтожается
    }
}

$db = new Database(); // Соединение открыто
// конец скрипта или unset($db)
// Соединение закрыто

__get и __set

Вызываются при обращении к несуществующим или недоступным свойствам:

class User
{
    private array $data = [];

    public function __set(string $name, mixed $value): void
    {
        echo "Устанавливаем {$name} = {$value}" . PHP_EOL;
        $this->data[$name] = $value;
    }

    public function __get(string $name): mixed
    {
        echo "Получаем {$name}" . PHP_EOL;
        return $this->data[$name] ?? null;
    }
}

$user = new User();
$user->name  = 'John';  // __set('name', 'John')
$user->email = '[email protected]'; // __set('email', ...)
echo $user->name;       // __get('name') → John
echo $user->age;        // __get('age') → null

__isset и __unset

class User
{
    private array $data = ['name' => 'John'];

    public function __isset(string $name): bool
    {
        return isset($this->data[$name]);
    }

    public function __unset(string $name): void
    {
        unset($this->data[$name]);
    }
}

$user = new User();
var_dump(isset($user->name)); // true  → __isset('name')
var_dump(isset($user->age));  // false → __isset('age')
unset($user->name);           // __unset('name')

__call и __callStatic

Вызываются при обращении к несуществующим методам:

class ApiClient
{
    public function __call(string $name, array $args): mixed
    {
        echo "Вызван метод {$name} с аргументами: " . implode(', ', $args) . PHP_EOL;
        // можно делать динамические запросы к API
        return $this->request($name, $args);
    }

    public static function __callStatic(string $name, array $args): mixed
    {
        echo "Статический вызов {$name}" . PHP_EOL;
        return null;
    }

    private function request(string $method, array $args): string
    {
        return "Результат {$method}";
    }
}

$api = new ApiClient();
$api->getUsers();          // Вызван метод getUsers
$api->createOrder(1, 100); // Вызван метод createOrder с аргументами: 1, 100
ApiClient::getInstance();  // Статический вызов getInstance

__toString

Вызывается когда объект используется как строка:

class Money
{
    public function __construct(
        private int    $amount,
        private string $currency = 'USD',
    ) {}

    public function __toString(): string
    {
        return "{$this->amount} {$this->currency}";
    }
}

$price = new Money(100, 'USD');
echo $price;              // 100 USD
echo "Цена: {$price}";   // Цена: 100 USD
$str = (string) $price;  // "100 USD"

__invoke

Вызывается когда объект используется как функция:

class Multiplier
{
    public function __construct(
        private int $factor
    ) {}

    public function __invoke(int $number): int
    {
        return $number * $this->factor;
    }
}

$double = new Multiplier(2);
$triple = new Multiplier(3);

echo $double(5);  // 10 — объект вызывается как функция
echo $triple(5);  // 15

// Можно передавать как callable
$numbers = [1, 2, 3, 4, 5];
$result  = array_map($double, $numbers);
// [2, 4, 6, 8, 10]

__clone

Вызывается при клонировании объекта:

class Order
{
    public function __construct(
        public string  $status,
        public Address $address, // вложенный объект
    ) {}

    public function __clone()
    {
        // Без этого address будет общим у оригинала и клона
        $this->address = clone $this->address;
    }
}

__sleep и __wakeup

Вызываются при сериализации и десериализации:

class User
{
    public string $name;
    public string $password;
    private $connection; // не хотим сериализовать соединение

    public function __sleep(): array
    {
        // Возвращаем только те свойства которые нужно сохранить
        return ['name']; // password тоже не сохраняем
    }

    public function __wakeup(): void
    {
        // Восстанавливаем соединение после десериализации
        $this->connection = new PDO('...');
    }
}

$user       = new User();
$user->name = 'John';

$serialized = serialize($user);   // __sleep — сохраняет только name
$restored   = unserialize($serialized); // __wakeup — восстанавливает соединение

__debugInfo

Контролирует что показывает var_dump():

class User
{
    public function __construct(
        public string $name,
        public string $password,
        public string $token,
    ) {}

    public function __debugInfo(): array
    {
        return [
            'name'     => $this->name,
            'password' => '***',  // скрываем пароль
            'token'    => '***',  // скрываем токен
        ];
    }
}

$user = new User('John', 'secret123', 'abc123token');
var_dump($user);
// name: 'John'
// password: '***'
// token: '***'