Magic methods: __construct, __destruct, __toString, __invoke
Concept
PHP's magic methods are predefined method names with special semantics — the engine calls them automatically in response to specific language events. They allow classes to customize fundamental behaviors: construction, destruction, string conversion, and invocation.
__construct(): Called by new ClassName(). Initializes the object. If a parent class has __construct, the child must explicitly call parent::__construct() — constructors are NOT automatically chained.
__destruct(): Called when the object is about to be garbage collected (when refcount drops to zero or at end of request). Use for cleanup: closing file handles, releasing non-memory resources. Don't rely on it for critical cleanup — throw exceptions from __construct instead, as destructors are called even if the constructor threw.
__toString(): Called when an object is used in a string context (echo $obj, "Hello $obj", explicit (string)$obj). Since PHP 8.0, classes implementing __toString implicitly implement the Stringable interface. Must return a string; throwing from __toString was allowed from PHP 7.4+.
__invoke(): Called when an object is called as a function ($obj(...args)). Makes the object a "callable." Common in middleware, command handlers, and Laravel jobs/listeners that are also callables. Checked by is_callable().
Code Example
<?php
declare(strict_types=1);
class TempFile
{
private string $path;
public function __construct(string $prefix = 'php')
{
$this->path = tempnam(sys_get_temp_dir(), $prefix);
echo "__construct: created {$this->path}\n";
}
public function write(string $data): void
{
file_put_contents($this->path, $data);
}
public function __toString(): string
{
return $this->path;
}
public function __destruct()
{
if (file_exists($this->path)) {
unlink($this->path);
echo "__destruct: deleted {$this->path}\n";
}
}
}
$file = new TempFile();
$file->write("hello");
echo "File path: $file\n"; // __toString called
// When $file goes out of scope: __destruct deletes the file
// __invoke — callable object
class Multiplier
{
public function __construct(private float $factor) {}
public function __invoke(float $value): float
{
return $value * $this->factor;
}
}
$double = new Multiplier(2.0);
$taxRate = new Multiplier(1.2);
echo $double(5.0); // 10.0 — __invoke called
echo $taxRate(100.0); // 120.0
// As callable
$prices = [10.0, 20.0, 50.0];
$doubled = array_map($double, $prices); // [20.0, 40.0, 100.0]
// Combining — Stringable + callable
class Formatter
{
public function __construct(private string $template) {}
public function __invoke(array $data): string
{
return preg_replace_callback('/\{(\w+)\}/', fn($m) => $data[$m[1]] ?? '', $this->template);
}
public function __toString(): string { return $this->template; }
}
$fmt = new Formatter('Hello, {name}!');
echo $fmt(['name' => 'Codrut']); // "Hello, Codrut!"
echo $fmt; // "Hello, {name}!" (template itself)