Skip to content

PHP Tutorial Object-Oriented PHP

Magic Methods

Lesson 209 of 369 2 min read By Deepak Paswan Updated Oct 5, 2026

Magic methods are special methods whose names start with two underscores. PHP calls them automatically at certain moments. You have already used one: __construct().

MethodCalled 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.

index.php
PHP
<?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";
Output
OUTPUT
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.

index.php
PHP
<?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;
Output
OUTPUT
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.

index.php
PHP
<?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);
Output
OUTPUT
You called doSomething with 2 argument(s)

Frameworks use this for things like dynamic query methods (whereName()).

__invoke()

Makes an object callable.

index.php
PHP
<?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]));
Output
OUTPUT
15
3, 6, 9

__clone()

Runs after an object is cloned, which is useful to copy inner objects (a deep copy).

index.php
PHP
<?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;
Output
OUTPUT
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.

info
Why this matters in Laravel
Laravel models use __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.