Magic Methods in PHP

Magic methods Before we move onto polymorphism, let us go over a few magic methods that are provided by PHP to perform operations such as property overloading, method overloading, and representing an object as text.

These magic methods are collections of special methods that respond to an event.

The magic methods follow a unique naming convention where the name is prepended by two underscores ("__"); one of the magic method that we have already worked with is the __construct() method that is automatically fired upon object instantiation.

A few other magic methods that we would work with are:

  • __destruct()
  • __get()
  • __set()
  • __toString()
  • __ clone()
  • __call()

__construct()

Automatically called when an object is created. It is commonly used to initialize object properties or perform setup tasks.

The constructor is optional. If defined, it executes during object instantiation.

class User {
    public $name;

    public function __construct($name) {
        $this->name = $name;
        echo "User $name created.\n";
    }
}

$user = new User("Alice");
// Output: User Alice created.

__destruct()

Automatically called when an object is destroyed, such as when the script ends or the object is explicitly unset.

Behavior: Often used for cleanup, like closing database connections or releasing resources.

class FileHandler {
    private $file;

    public function __construct($filename) {
        $this->file = fopen($filename, "w");
        echo "File opened.\n";
    }

    public function __destruct() {
        fclose($this->file);
        echo "File closed.\n";
    }
}

$fileHandler = new FileHandler("example.txt");
unset($fileHandler);  
// Output: File closed.

__get($name)

Triggers when attempting to access an undefined or inaccessible property of an object.

Useful for dynamic properties or lazy-loading logic.

class Product {
    private $attributes = ['price' => 100, 'name' => 'Laptop'];

    public function __get($property) {
        return $this->attributes[$property] ?? "Property does not exist.";
    }
}

$product = new Product();
echo $product->price;  // Output: 100
echo $product->color;  // Output: Property does not exist.

__set($name, $value)

Invoked when attempting to set a value to an undefined or inaccessible property.

Useful for dynamic or computed properties.

class Product {
    private $attributes = [];

    public function __set($property, $value) {
        $this->attributes[$property] = $value;
    }

    public function __get($property) {
        return $this->attributes[$property] ?? null;
    }
}

$product = new Product();
$product->name = "Laptop";
echo $product->name;  // Output: Laptop

__isset($name)

Called when using isset() or empty() on an undefined or inaccessible property.

Used to check if a dynamic property exists.

class Product {
    private $attributes = ['name' => 'Laptop'];

    public function __isset($property) {
        return isset($this->attributes[$property]);
    }
}

$product = new Product();
var_dump(isset($product->name));  // Output: bool(true)
var_dump(isset($product->price)); // Output: bool(false)

__unset($name)

Called when unset() is used on an undefined or inaccessible property.

Can remove dynamically defined properties.

class Product {
    private $attributes = ['name' => 'Laptop'];

    public function __unset($property) {
        unset($this->attributes[$property]);
    }
}

$product = new Product();
unset($product->name);

__call($name, $arguments)

Called when invoking an inaccessible or undefined method.

Useful for implementing a proxy or delegation pattern.

class Calculator {
    public function __call($name, $arguments) {
        if ($name == 'add') {
            return array_sum($arguments);
        }

        return "Method $name does not exist.";
    }
}

$calc = new Calculator();
echo $calc->add(10, 20, 30);  // Output: 60
echo $calc->subtract(10, 5); // Output: Method subtract does not exist.

__callStatic($name, $arguments)

Invoked for inaccessible or undefined static methods.

Useful for handling static method calls dynamically.

class Math {
    public static function __callStatic($name, $arguments) {
        if ($name == 'multiply') {
            return array_product($arguments);
        }

        return "Static method $name does not exist.";
    }
}

echo Math::multiply(2, 3, 4);  // Output: 24

__toString()

Defines the string representation of an object. Automatically called when an object is used in a string context.

class User {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function __toString() {
        return "User: $this->name";
    }
}

$user = new User("Alice");
echo $user;  // Output: User: Alice

__invoke()

Called when an object is used as a function. Useful for implementing callable objects.

class Greeting {
    public function __invoke($name) {
        return "Hello, $name!";
    }
}

$greet = new Greeting();
echo $greet("Alice");  // Output: Hello, Alice!

__clone()

Triggers when an object is cloned using clone. Can customize the cloning behavior.

class Person {
    public $name;

    public function __clone() {
        $this->name = "Cloned - $this->name";
    }
}

$person = new Person();
$person->name = "John";
$clone = clone $person;
echo $clone->name;  // Output: Cloned - John

__sleep() and __wakeup()

Used during serialization (serialize) and deserialization (unserialize).

  • __sleep() defines which properties to serialize.
  • __wakeup() reinitializes the object after deserialization.
class Connection {
    private $connection;

    public function __sleep() {
        return [];
    }

    public function __wakeup() {
        $this->connection = "Reconnected";
    }
}

__serialize() and __unserialize()

Used for custom serialization/deserialization logic in PHP 7.4+.

class Data {
    private $values;

    public function __serialize(): array {
        return ['values' => $this->values];
    }

    public function __unserialize(array $data): void {
        $this->values = $data['values'];
    }
}

__debugInfo()

Defines what to display when var_dump() is called on an object.

class Secret {
    private $password = "hidden";

    public function __debugInfo() {
        return ['password' => '****'];
    }
}

$secret = new Secret();
var_dump($secret);  // Output: array(1) { ["password"]=> string(4) "****" }

These magic methods are versatile and powerful tools in PHP OOP, enabling custom behaviors for objects and making classes more dynamic and flexible.