Magic methods are special methods whose names start with two underscores. PHP calls them automatically at certain moments. You have already used one: __construct().
| Method | Called when |
|---|---|
__construct() | An object is created |
__destruct() | An object is destroyed |
__toString() | The object is used as a string |
__get($name) | A property that is not accessible is read |
__set($name, $value) | A property that is not accessible is written |
__isset($name) / __unset($name) | isset() / unset() on such a property |
__call($name, $args) | An inaccessible method is called |
__callStatic() | The same, for static calls |
__invoke() | The object is called like a function |
__clone() | The object is cloned |
__toString()
Lets you turn an object into text.
<?php
class Product
{
public function __construct(private string $name, private float $price) {}
public function __toString(): string
{
return $this->name . " (" . number_format($this->price, 2) . ")";
}
}
$p = new Product("Notebook", 80);
echo "Item: $p";
Item: Notebook (80.00)
A class with __toString() automatically implements the Stringable interface.
__get() and __set()
They catch reads and writes to properties that do not exist or are private.
<?php
class Settings
{
private array $data = [];
public function __get(string $name): mixed
{
return $this->data[$name] ?? null;
}
public function __set(string $name, mixed $value): void
{
$this->data[$name] = $value;
}
}
$s = new Settings();
$s->theme = "dark";
echo $s->theme;
dark
This is flexible, but your editor cannot help with these properties, and typos go unnoticed. Use it sparingly.
__call()
Catches calls to methods that do not exist.
<?php
class Magic
{
public function __call(string $name, array $arguments): string
{
return "You called $name with " . count($arguments) . " argument(s)";
}
}
echo (new Magic())->doSomething(1, 2);
You called doSomething with 2 argument(s)
Frameworks use this for things like dynamic query methods (whereName()).
__invoke()
Makes an object callable.
<?php
class Multiplier
{
public function __construct(private int $factor) {}
public function __invoke(int $n): int
{
return $n * $this->factor;
}
}
$triple = new Multiplier(3);
echo $triple(5) . "\n";
echo implode(", ", array_map($triple, [1, 2, 3]));
15
3, 6, 9
__clone()
Runs after an object is cloned, which is useful to copy inner objects (a deep copy).
<?php
class Address
{
public string $city = "Pune";
}
class Person
{
public Address $address;
public function __construct()
{
$this->address = new Address();
}
public function __clone()
{
$this->address = clone $this->address;
}
}
$a = new Person();
$b = clone $a;
$b->address->city = "Delhi";
echo $a->address->city;
Pune
Without __clone(), both people would share one Address object.
Do not invent your own double-underscore names
Names starting with __ are reserved by PHP. Only use the ones PHP defines.
Why this matters in Laravel
__get(), __call() and __callStatic() heavily, which is why you can write $user->name and User::where(...) with no matching methods in the class. Now you know where that “magic” comes from.