Magic Methods
The special __-prefixed methods PHP calls automatically for construction, string conversion, and dynamic property access.
2 min read
PHP reserves method names starting with two underscores as magic methods — hooks the engine calls automatically in specific situations, rather than being called directly by your code.
__construct and __destruct
<?php
class DatabaseConnection {
public function __construct() {
echo "Connecting...\n";
}
public function __destruct() {
echo "Closing connection.\n";
}
}
$db = new DatabaseConnection();__construct() (already covered) runs on creation; __destruct() runs automatically when an object is garbage-collected — typically at the end of the script, or earlier if nothing else references it. It's most useful for releasing an external resource (a file handle, a network connection) deterministically rather than waiting for the script to simply end.
__toString: controlling string conversion
<?php
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: $price"; // "Price: 19.99"Without __toString(), trying to use an object where a string is expected (like inside echo or string interpolation) throws an error. Defining it lets an object participate naturally in string contexts, which is why classes representing a value (money, a date, a URL) commonly implement it.
__get and __set: intercepting property access
<?php
class Config {
private array $data = [];
public function __get($name) {
return $this->data[$name] ?? null;
}
public function __set($name, $value) {
$this->data[$name] = $value;
}
}
$config = new Config();
$config->timeout = 30; // triggers __set
echo $config->timeout; // triggers __get, prints 30__get() and __set() fire automatically when code accesses a property that isn't actually declared (or isn't accessible) on the object — here, Config has no real timeout property, but the magic methods make it behave as if it does, backed by the private $data array. This underpins how some frameworks implement flexible, dynamic-feeling configuration or model objects.
__call: intercepting method calls
<?php
class ApiClient {
public function __call($name, $arguments) {
echo "Calling method '$name' with: " . implode(", ", $arguments);
}
}
$client = new ApiClient();
$client->getUser(42); // "Calling method 'getUser' with: 42"__call() fires when code calls a method that doesn't exist on the object. Frameworks use this to build fluent, dynamic-feeling APIs (like a query builder that seems to have a method for every possible database column) without hand-writing every possible method name in advance.
A word of caution
Magic methods are powerful but make code harder to trace — an IDE can't "go to definition" on a property or method that only exists via __get/__call, and a typo silently falls into the magic method instead of raising a clear "method not found" error. Reach for them when building a library or framework-level abstraction; for everyday application code, an explicitly declared property or method is almost always clearer.
Test what you just learned
4 quick questions. Get all of them right to unlock the next lesson.
You can take the quiz without an account — logging in just lets your result count toward your progress.