LearnContact
Lesson 5021 min read

Magic Methods

Learn how PHP magic methods like __toString, __get, __set, and __call let PHP call special behavior automatically.

Introduction

You have already used two special methods without necessarily thinking of them that way: `__construct()`, which PHP calls automatically when an object is created, and `__destruct()`, which PHP calls automatically when an object is destroyed. These are examples of a broader category called magic methods.

Magic methods are special methods, always prefixed with a double underscore, that PHP invokes automatically in specific situations — converting an object to a string, accessing an undefined property, or calling an undefined method. They let your objects respond intelligently to situations you cannot fully predict in advance.

What You Will Learn
  • What magic methods are and why they start with `__`.
  • A quick recap of `__construct` and `__destruct`.
  • How `__toString()` controls converting an object to a string.
  • How `__get` and `__set` intercept access to undefined properties.
  • How `__call` intercepts calls to undefined methods.

What Are Magic Methods?

A magic method is a method with a reserved name, always beginning with two underscores, that PHP calls automatically at a specific moment — not because your code explicitly calls it, but because PHP's engine triggers it in response to something happening to the object.

Magic MethodTriggered When
__construct()An object is created with `new`
__destruct()An object is destroyed or the script ends
__toString()An object is used in a string context, like echo
__get($name)Reading an inaccessible or undefined property
__set($name, $value)Writing to an inaccessible or undefined property
__call($name, $args)Calling an inaccessible or undefined method

Recap: __construct and __destruct

You met these two in an earlier lesson. `__construct()` runs automatically right after an object is created, typically to initialize its properties. `__destruct()` runs automatically right before an object is removed from memory, often used for cleanup like closing a file handle.

construct-destruct-recap.php
<?php
class Connection
{
    public function __construct(private string $name)
    {
        echo "Opening connection: {$this->name}\n";
    }

    public function __destruct()
    {
        echo "Closing connection: {$this->name}\n";
    }
}

$conn = new Connection("Database");
echo "Using connection...\n";
Output
Opening connection: Database
Using connection...
Closing connection: Database

__toString

By default, PHP does not know how to display an object as text. The `__toString()` magic method lets you define exactly what should happen whenever an object is used somewhere a string is expected, such as inside `echo` or string concatenation.

tostring-example.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);
    }
}

$product = new Product("Wireless Mouse", 24.5);
echo $product;
Output
Wireless Mouse - $24.50

Without `__toString()`, trying to `echo $product` directly would cause a fatal error, since PHP would not know how to represent the object as text.

__get and __set

`__get($name)` is called automatically when code tries to read a property that is either undefined or inaccessible (like a private property from outside the class). `__set($name, $value)` is called automatically when code tries to write to such a property. Together, they let you intercept and control property access.

get-set-example.php
<?php
class Settings
{
    private array $data = [];

    public function __get(string $name)
    {
        return $this->data[$name] ?? null;
    }

    public function __set(string $name, $value): void
    {
        echo "Setting '$name' to '$value'\n";
        $this->data[$name] = $value;
    }
}

$settings = new Settings();
$settings->theme = "dark";
echo $settings->theme;
Output
Setting 'theme' to 'dark'
dark
Only for Inaccessible Properties

__get and __set only trigger for properties that are undefined or not directly accessible from the calling context. If a public property with that name already exists, PHP accesses it directly and skips these magic methods entirely.

__call

`__call($name, $arguments)` is called automatically whenever code tries to call a method that does not exist (or is not accessible) on an object. It receives the method name that was attempted and an array of the arguments passed.

call-example.php
<?php
class ApiClient
{
    public function __call(string $name, array $arguments)
    {
        $endpoint = strtolower($name);
        return "Calling endpoint '/$endpoint' with " . count($arguments) . " argument(s)";
    }
}

$client = new ApiClient();
echo $client->getUsers(1, 20);
Output
Calling endpoint '/getusers' with 2 argument(s)

This is exactly the technique many frameworks use to build flexible, dynamic APIs — methods that were never explicitly written can still be "called" and handled generically.

Worked Example: Money Class

Here is a small `Money` class that uses `__toString()` to make displaying money values natural and readable anywhere a string is expected.

money.php
<?php
class Money
{
    public function __construct(
        private float $amount,
        private string $currency = "USD"
    ) {}

    public function add(Money $other): Money
    {
        return new Money($this->amount + $other->amount, $this->currency);
    }

    public function __toString(): string
    {
        return number_format($this->amount, 2) . " {$this->currency}";
    }
}

$price = new Money(19.99);
$tax = new Money(1.60);
$total = $price->add($tax);

echo "Price: $price\n";
echo "Tax: $tax\n";
echo "Total: $total";
Output
Price: 19.99 USD
Tax: 1.60 USD
Total: 21.59 USD

Notice `$price`, `$tax`, and `$total` are all `Money` objects, but embedding them directly into strings just works — `__toString()` handles the conversion automatically.

Common Mistakes

Avoid These Mistakes
  • Forgetting `__toString()` must return a string — returning anything else causes a fatal error.
  • Overusing `__get`/`__set`/`__call` for everything instead of declaring real, explicit properties and methods.
  • Assuming `__get`/`__set` fire for public properties too — they only trigger for undefined or inaccessible ones.
  • Forgetting `__call` receives arguments as an array, not as individual parameters.

Best Practices

  • Implement `__toString()` on any class that represents a value naturally shown as text, like Money or Product.
  • Reserve `__get`/`__set` for genuine cases like lazy-loading or wrapping dynamic data, not as a substitute for real properties.
  • Use `__call` sparingly, and document what dynamic method names it supports.
  • Prefer explicit, declared methods and properties whenever possible — magic methods trade clarity for flexibility.

Frequently Asked Questions

Are there other magic methods besides the ones covered here?

Yes. PHP also has `__isset`, `__unset`, `__callStatic`, `__invoke`, `__clone`, and more, each triggered by a specific situation.

What happens if I call an undefined method and there is no __call?

PHP throws a fatal "Call to undefined method" error, since there is no magic method to intercept and handle the call.

Can __toString() be used in string concatenation, not just echo?

Yes, __toString() is triggered any time an object is used in any string context, including concatenation with the dot operator, not only echo.

Do magic methods slow down my code?

They add a small amount of overhead compared to direct property or method access, but for typical applications this difference is negligible.

Can a class define __get without __set, or vice versa?

Yes, you can implement just one of the pair. Without __set defined, attempting to write to an inaccessible property causes a fatal error.

Key Takeaways

  • Magic methods are special methods starting with `__` that PHP calls automatically.
  • __construct and __destruct run automatically on object creation and destruction.
  • __toString() controls how an object is converted to a string.
  • __get and __set intercept access to undefined or inaccessible properties.
  • __call intercepts calls to undefined or inaccessible methods.

Summary

Magic methods give your classes hooks into moments PHP normally handles silently — object creation, string conversion, undefined property access, and undefined method calls. Used well, they make objects feel natural to work with; used carelessly, they can hide what your code is actually doing.

In this lesson, you reviewed __construct and __destruct, and learned __toString, __get, __set, and __call, finishing with a Money class example. Next, you will learn about static properties and methods, which belong to the class itself rather than to any individual instance.

Lesson 50 Completed
  • You understand what magic methods are and when PHP triggers them.
  • You can implement __toString() to control string conversion.
  • You can use __get and __set to intercept property access.
  • You can use __call to intercept undefined method calls.
Next Lesson →

Static Properties & Methods