🧱 Суть

Магические методы – это специальные методы PHP, которые начинаются с двух подчёркиваний:

__

PHP вызывает их автоматически в определённых ситуациях.

Например:

  • создание объекта → __construct()
  • обращение к недоступному свойству → __get()
  • вызов недоступного метода → __call()
  • преобразование объекта в строку → __toString()

Пример:

class User
{
    public function __construct()
    {
        echo "Объект создан";
    }
}
 
$user = new User();

Метод __construct() вызовется автоматически.

📦 Проблема

1. Нужно выполнять код при создании объекта

Без конструктора пришлось бы делать вручную:

$user = new User();
 
$user->init();

Можно забыть вызвать:

$user->init();

или создать объект в неправильном состоянии.

2. Нужно контролировать доступ к закрытым данным

Например:

class User
{
    private string $name;
}

Прямой доступ запрещён:

$user->name;

Но иногда нужно перехватывать такие обращения.

3. Необходимо автоматическое поведение объектов

Например:

  • логирование
  • сериализация
  • преобразование в JSON
  • обработка неизвестных методов

Для этого PHP предоставляет магические методы.

✅ Решение

Использовать магические методы для специальных сценариев жизненного цикла объекта.

Основные:

МетодКогда вызывается
__construct()создание объекта
__destruct()уничтожение объекта
__get()чтение недоступного свойства
__set()запись недоступного свойства
__isset()проверка isset()
__unset()удаление свойства
__call()вызов недоступного метода
__callStatic()вызов недоступного static-метода
__toString()объект преобразуют в строку
__invoke()объект вызывают как функцию
__clone()клонирование объекта

💻 Код

__construct()

Конструктор вызывается при создании объекта.

Пример:

class User
{
    public string $name;
 
    public function __construct(string $name)
    {
        $this->name = $name;
    }
}

Использование:

$user = new User("Alex");

То же самое, что:

Создать объект

Вызвать __construct()

Заполнить данные

Типичное применение – инициализация зависимостей:

class UserService
{
    public function __construct(
        private Database $db
    ) {}
}

Теперь объект сразу получает необходимые зависимости.

__destruct()

Вызывается при уничтожении объекта.

Пример:

class Connection
{
    public function __destruct()
    {
        echo "Соединение закрыто";
    }
}

Используется редко.

Например:

  • закрытие ресурсов
  • очистка временных данных

__get()

Вызывается при чтении недоступного свойства.

Пример:

class User
{
    private string $name = "Alex";
 
    public function __get($property)
    {
        return $this->$property;
    }
}

Теперь:

$user->name;

вызовет:

__get("name")

Применяется, например, при создании “динамических” свойств:

class Config
{
    private array $data = [
        'app' => 'My App'
    ];
 
    public function __get($key)
    {
        return $this->data[$key];
    }
}

Использование:

echo $config->app;

__set()

Вызывается при записи в недоступное свойство.

Пример:

class User
{
    private array $data = [];
 
    public function __set($key, $value)
    {
        $this->data[$key] = $value;
    }
}

Теперь:

$user->name = "Alex";

попадёт в:

__set("name", "Alex")

__isset()

Вызывается при:

isset()

Пример:

class User
{
    private array $data = [];
 
    public function __isset($key)
    {
        return isset($this->data[$key]);
    }
}

Теперь:

isset($user->name);

работает через:

__isset("name")

__unset()

Вызывается при:

unset()

Пример:

public function __unset($key)
{
    unset($this->data[$key]);
}

__call()

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

Пример:

class Api
{
    public function __call($method, $arguments)
    {
        echo "Метод $method не найден";
    }
}

Вызов:

$api->sendRequest();

Запустит:

__call(
    "sendRequest",
    []
)

__callStatic()

То же самое, но для статических методов.

class Helper
{
    public static function __callStatic($name, $arguments)
    {
        echo $name;
    }
}

Вызов:

Helper::test();

__toString()

Вызывается, когда объект пытаются вывести как строку.

Без него:

echo $user;

даст ошибку.

С ним:

class User
{
    public function __toString()
    {
        return "User object";
    }
}

Теперь:

echo $user;

Результат:

User object

__invoke()

Позволяет использовать объект как функцию.

Пример:

class Logger
{
    public function __invoke(string $message)
    {
        echo $message;
    }
}

Теперь:

$logger = new Logger();
 
$logger("Ошибка");

Работает как:

$logger->__invoke("Ошибка");

__clone()

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

$user2 = clone $user;

Пример:

class User
{
    public function __clone()
    {
        echo "Клон создан";
    }
}

Магические методы и типичная архитектура

Чаще всего в реальных проектах встречаются:

__construct()

Практически везде:

class UserController
{
    public function __construct(
        private UserService $service
    ) {}
}

__toString()

Например:

  • модели
  • Value Objects
  • UUID

__get() / __set()

Используются реже.

Чаще вместо них:

$user->getName();
$user->setName();

потому что это:

  • понятнее
  • безопаснее
  • проще для IDE

Частые ошибки

Использование __get() вместо нормальных методов

Плохо:

$user->password;

через магию.

Лучше:

$user->getPasswordHash();

Скрытая логика

Плохо:

$user->something;

а внутри:

__get()
{
    // сложный запрос в БД
}

Проблема: код выглядит простым, но выполняет тяжёлые операции.

Слишком много магии

Чем больше скрытого поведения:

  • тем сложнее читать код
  • сложнее искать ошибки
  • хуже поддержка IDE

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

Магический методОбычный метод
Вызовавтоматически PHPвручную
Видимостьскрытаяявная
Удобствоиногда вышепонятнее
Контрольменьшебольше

🎯 Вывод

  • магические методы начинаются с __
  • PHP вызывает их автоматически в определённых ситуациях
  • __construct() используется для инициализации объекта
  • __get() и __set() перехватывают доступ к свойствам
  • __call() обрабатывает неизвестные методы
  • __toString() позволяет выводить объект как строку
  • магия полезна для спецслучаев, но не должна заменять обычный понятный код
  • в современных PHP-проектах чаще всего используется __construct()

🔗 Связано