PHP calls a small set of specially-named methods automatically, in response to specific operations on an object — reading a property that doesn't exist, treating an object as a string, and a few others. __construct() from earlier lessons is the most common one; here are the rest worth knowing.
class Money {
public function __construct(private int $cents) {}
public function __toString(): string {
return '$' . number_format($this->cents / 100, 2);
}
}
$price = new Money(1999);
echo $price; // $19.99 — echo calls __toString() automaticallyRuns when code tries to read or write a property that isn't explicitly declared — useful for computed or dynamically-stored properties.
class Config {
private array $data = [];
public function __get(string $name) {
return $this->data[$name] ?? null;
}
public function __set(string $name, $value): void {
$this->data[$name] = $value;
}
}
$config = new Config();
$config->siteName = 'My App'; // triggers __set()
echo $config->siteName; // triggers __get() — "My App"class ApiClient {
public function __call(string $method, array $args) {
return "Called $method with " . count($args) . " argument(s)";
}
}
$client = new ApiClient();
echo $client->getUsers(1, 2); // "Called getUsers with 2 argument(s)"| Method | Runs when... |
|---|---|
| __construct() | An object is created |
| __destruct() | An object is destroyed or the script ends |
| __toString() | An object is used in a string context (echo, concatenation) |
| __get() / __set() | An undefined property is read or written |
| __call() | An undefined method is called |
A real trade-off, not a free upgrade
Magic methods make code harder to trace — a click-to-definition on $config->siteName won't lead anywhere obvious. Use them for a genuine, specific need (a config object, a lightweight ORM), not as a default way to write a class.