🧱 Суть
Магические методы – это специальные методы 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()