Магические методы — это специальные методы которые PHP вызывает автоматически в определённых ситуациях. Начинаются с двойного подчёркивания __.
Шпаргалка
| Метод | Когда вызывается |
|---|---|
__construct | при new |
__destruct | при уничтожении объекта |
__get | чтение несуществующего свойства |
__set | запись несуществующего свойства |
__isset | isset() на несуществующем свойстве |
__unset | unset() на несуществующем свойстве |
__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: '***'