PHP Magic Methods Explained

Last Updated: 21 Feb, 2023

What are Magic Methods in PHP?

Magic Methods are special types of methods in PHP that allows you to perform certain special actions. By convention, magic methods start with a double underscore (__). PHP also reserves the names of magic methods and they are always magical in PHP classes. We are not allowed to define functions with these names in any of our classes unless you want the magical functionality associated with them.

Points to note:

  • Magic methods always start with a double underscore.
  • Magic Methods in any class must be declared as public.
  • These methods are automatically called when certain conditions are met and you no need to call explicitly.
  • All these methods are magical in all PHP classes, so we cannot define any functions with these names.

List of all Magic Methods avaiable in PHP:

  • __construct() - Triggered when an object of a class is created.
  • __destruct() - Triggered when an object of a class is destroyed.
  • __call($name, $arguments) - Triggered when an inaccessible or undefined method is called in an object context.
  • __callStatic($name, $arguments) - Triggered when an inaccessible or undefined method is called in a static context.
  • __get($name) - Triggered when you try to read data from inaccessible (private or protected) or non-existing properties.
  • __set($name, $value) - Triggered when you try to write data to inaccessible (private or protected) or non-existing properties.
  • __isset($name) - Triggered when you call isset() or empty() method on any inaccessible (private or protected) or non-existing properties.
  • __unset($name) - Triggered when you call unset() method on inaccessible (private or protected) or non-existing properties.
  • __sleep() - Triggered when you call serialize() function on an object.
  • __wakeup() - Triggered when you call unserialize() function on an object.
  • __serialize() - Triggered when you call serialize() method.
  • __unserialize() - Triggered when you call unserialize() method.
  • __toString() - Triggered when you try to print an object. Specially when you pass an object to echo() or print() function.
  • __invoke() - Triggered when you try to call an object as a function.
  • __set_state($array) - Triggered when you try to call the var_export() function.
  • __clone() - Triggered when you try to make a clone of an exsting object by calling clone keyword.
  • __debugInfo() - Triggered when you try to dump an object using var_dump() function.

Let's go through all the magic methods one-by-one and have the clear understanding of it.

The __construct() and __destruct() Magic Methods

This magic method gets called automatically whenever an object of a particular class is created. The purpose of this method is to assign default values to object propertiesN number of arguments can be defined here that will be passed while when objects are created.

This magic method gets called as soon as when an object of a class is destroyed. It is also gets called whenever any script is stopped or exited. The main aim of this method is to save the state of the object and perform any cleanup if required.

Example:

<?php
class Product
{
	private $name;
	private $mrp;
	private $price;
	public function __construct($name, $mrp, $price)
	{
		$this->name = $name;
		$this->mrp = $mrp;
		$this->price = $price;
		echo "Product '$name' has MRP: $mrp and Price: $price. \n";
	}
        public function __destruct()
	{
		echo "Calling destructor for '$this->name'. \n";
	}
}

//create an object of Product class
$product1 = new Product('Blue Shirt', 1000, 700);
/* OUTPUT: Product 'Blue Shirt' has MRP: 1000 and Price: 700. */

//create another object of Product class
$product2 = new Product('Red Shirt', 1500, 1200);
/* OUTPUT: Product 'Red Shirt' has MRP: 1500 and Price: 1200. */

/*
Calling destructor for 'Red Shirt'.
Calling destructor for 'Blue Shirt'.
*/
?>

The __call($name, $arguments) and __callStatic($name, $arguments) Magic Methods

The __call() magic method gets called when an undefined or inaccessible method is called in an object context. The __callStatic() magic method gets called when an undefined or inaccessible method is called in a static context. The $name parameter is the name of the method being called. The $arguments parameter is an enumerated array that contains the parameters passed to the $name method.

Example:

<?php
class Product
{
    private $name;
    private $mrp;
    private $price;
    public function __construct($name, $mrp, $price)
    {
        $this->name = $name;
        $this->mrp = $mrp;
        $this->price = $price;
        echo "Product '$name' has MRP: $mrp and Price: $price. \n";
    }

    public function __call($name, $arguments)
    {
        echo "Calling object method '$name' with parameters: ".implode(',', $arguments).".\n";
    }

    public static function __callStatic($name, $arguments)
    {
        echo "Calling static method '$name' with parameters: ".implode(',', $arguments).".\n";
    }
}

//create an object of Product class
$product = new Product('Blue Shirt', 1000, 700);
/* OUTPUT: Product 'Blue Shirt' has MRP: 1000 and Price: 700. */

//call undefined method in object context
$product->showProductName('ABC');
/* OUTPUT: Calling object method 'showProductName' with parameters: ABC. */

//call undefined method in static context
Product::showProductName('XYZ');
/* OUTPUT: Calling static method 'showProductName' with parameters: XYZ. */
?>

The __set($name, $value) and __get($name) Magic Methods

The __set() method gets called when you try to write data to inaccessible (private or protected) or non-existing properties. The __get() method gets called when you try to read data from inaccessible (private or protected) or non-existing properties. The $name parameter in the method is the name of the property being interact with.

Example:

<?php
class Product
{
	private $name;
    private $mrp;
    private $price;
    public function __construct($name, $mrp, $price)
    {
        $this->name = $name;
        $this->mrp = $mrp;
        $this->price = $price;
        echo "Product '$name' has MRP: $mrp and Price: $price. \n";
    }

	public function __set($name, $value)
	{
		echo "Trying to set ".$name." with ".$value." that is either inaccessible or non-existing property.\n";
	}

	public function __get($name)
	{
		echo "Trying to get ".$name." that is either inaccessible or non-existing property.\n";
	}
}

//create an object of Product class
$product = new Product('Blue Shirt', 1000, 700);
/* OUTPUT: Product 'Blue Shirt' has MRP: 1000 and Price: 700. */

//try to set value to discount (inaccessible or non-existing property)
$product->discount = 100;
/* OUTPUT: Trying to set discount with 100 that is either inaccessible or non-existing property. */

//try to get value from discount (inaccessible or non-existing property)
$discount = $product->discount;
/* OUTPUT: Trying to get discount that is either inaccessible or non-existing property. */
?>

The __isset($name) and __unset($name) Magic Methods

The __isset() method gets called when we call isset() or empty() method on inaccessible (private or protected) or non-existing properties. The __unset() method gets called when we call unset() method on inaccessible (private or protected) or non-existing properties. The $name argument in the method is the name of the property being interact with.

Example:

<?php
class Product
{
    private $name;
    private $mrp;
    private $price;
    public function __construct($name, $mrp, $price)
    {
        $this->name = $name;
        $this->mrp = $mrp;
        $this->price = $price;
        echo "Product '$name' has MRP: $mrp and Price: $price. \n";
    }

    public function __isset($name)
    {
        echo "Trying to check ".$name." that is either inaccessible or non-existing property.\n";
    }

    public function __unset($name)
    {
        echo "Trying to unset ".$name." that is either inaccessible or non-existing property.\n";
    }
}

//create an object of Product class
$product = new Product('Blue Shirt', 1000, 700);
/* OUTPUT: Product 'Blue Shirt' has MRP: 1000 and Price: 700. */

//try to check discount (inaccessible or non-existing property)
if (isset($product->discount) and !empty($product->discount)){
    echo "Discount is: ".$product->discount.".\n";
}
/* OUTPUT: Trying to check discount that is either inaccessible or non-existing property. */

//try to unset discount (inaccessible or non-existing property)
unset($product->discount);
/* OUTPUT: Trying to unset discount that is either inaccessible or non-existing property. */
?>

The __sleep() and __wakeup() Magic Methods

The __sleep() magic method gets called when you call serialize() function on any object. The intended use of __sleep() is to commit any pending data or perform any cleanup tasks. This function is also useful whenever a very large object is not needed to be saved completely.

The __wakeup() magic method gets called when you call unserialize() function on any object. The intended use of __wakeup() is to perform reconnection to any database that might have lost during serialization andalso perform other reinitialization tasks.

Example:

<?php
class DBConnection
{
	protected $connection;
	private $dsn, $username, $password;
	public function __construct($dsn, $username, $password)
	{
		$this->dsn = $dsn;
		$this->username = $username;
		$this->password = $password;
		$this->connect();
	}

	private function connect()
	{
		$this->connection = new PDO($this->dsn, $this->username, $this->password);
	}

	public function __sleep()
	{
		return array('mysql:host=127.0.0.1;dbname=test', 'mydbuser', 'mydbpassword');
	}

	public function __wakeup()
	{
		$this->connect();
	}
}
?>

The __serialize() and __unserialize() Magic Methods

The __serialize() magic method gets called when you call serialize() function. The purpose of the __serialize() is to define any serialized form of an object. The serialize() method will check if the class contains a function called __serialize(). If so, that function is first executed before any serialization action. The serialize() method must always return an associative array of key/value pairs. If fails to do so it will throw an TypeError.

The __unserialize() magic method gets called when you call unserialize() function. Th purpose of the __unserialize() method is to convert any serialized string into an object. The unserialize() method accepts a single serialized variable as an srgument and converts it back to the actual PHP value.

Example:

<?php
class DBConnection
{
	protected $connection;
	private $dsn, $username, $password;
	public function __construct($dsn, $username, $password)
	{
		$this->dsn = $dsn;
		$this->username = $username;
		$this->password = $password;
		$this->connect();
	}

	private function connect()
	{
		$this->connection = new PDO($this->dsn, $this->username, $this->password);
	}

	public function __serialize(): array
	{
		return array(
			'dsn' => $this->dsn,
			'username' => $this->username,
			'password' => $this->password,
		);
	}

	public function __unserialize(array $data): void
	{
		$this->dsn = $data['dsn'];
		$this->username = $data['username'];
		$this->password = $data['password'];
		$this->connect();
	}
}
?>

The __invoke() Magic Method

The __invoke() magic method gets called when you try to call any object as a function. The intended use of this function is whenever you need a callable object that has to maintain some internal state.

Example:

<?php
class Product
{
    private $name;
    private $mrp;
    private $price;
    public function __construct($name, $mrp, $price)
    {
        $this->name = $name;
        $this->mrp = $mrp;
        $this->price = $price;
        echo "Initializing object - Name: '$name' has MRP: $mrp and Price: $price. \n";
    }

    public function __invoke($name, $mrp, $price)
    {
        echo "Calling object as function - Name: $name, MRP: $mrp, Price: $price.\n";
    }
}

//create an object of Product class
$product = new Product('Blue Shirt', 1000, 700);
/* OUTPUT: Initializing object - Name: 'Blue Shirt' has MRP: 1000 and Price: 700.  */

//call object as function
$product('Red Shirt', 1200, 600);
/* OUTPUT: Calling object as function - Name: Red Shirt, MRP: 1200, Price: 600. */
?>

The __toString() Magic Method

The __toString() magic method gets called when you try to print an object specially whenever you pass an object to echo() or print() function. Since an object is not a string, the __toString() function is responsible for handling the transformation of the object into some string representation.

Example:

<?php
class Product
{
    private $name;
    private $mrp;
    private $price;
    public function __construct($name, $mrp, $price)
    {
        $this->name = $name;
        $this->mrp = $mrp;
        $this->price = $price;
        echo "Initializing object - Name: '$name' has MRP: $mrp and Price: $price. \n";
    }

    public function __toString()
    {
        echo "Printing object as string. \n";
    }
}

//create an object of Product class
$product = new Product('Blue Shirt', 1000, 700);
/* OUTPUT: Initializing object - Name: 'Blue Shirt' has MRP: 1000 and Price: 700.  */

//print object as string
echo $product;;
/* OUTPUT: Printing object as string. */
?>

The __clone() Magic Method

The __clone() magic method gets called whenever you try to make a clone of any exsting object by calling clone keyword.

Example:

<?php
class Product
{
    private $name;
    private $mrp;
    private $price;
    public function __construct($name, $mrp, $price)
    {
        $this->name = $name;
        $this->mrp = $mrp;
        $this->price = $price;
        echo "Initializing object - Name: '$name' has MRP: $mrp and Price: $price. \n";
    }

    public function __clone()
    {
        echo __METHOD__." You are cloning the object. \n";
    }
}

//create an object of Product class
$product = new Product('Blue Shirt', 1000, 700);
/* OUTPUT: Initializing object - Name: 'Blue Shirt' has MRP: 1000 and Price: 700.  */

//clone the object
$product2 = clone $product;
/* OUTPUT: Product::__clone You are cloning the object.  */
?>

The __debugInfo() Magic Method

The __debugInfo() magic method gets called whenever you try to dump an object using var_dump() method. So, if you have not defined __debugInfo() in your php class, it will dump all the private, protected and public properties. The intended use of __debugInfo() is to put restriction on some information that is displayed while dumping.

Example:

<?php
class Product
{
    private $name;
    private $mrp;
    private $price;
    public function __construct($name, $mrp, $price)
    {
        $this->name = $name;
        $this->mrp = $mrp;
        $this->price = $price;
        echo "Initializing object - Name: '$name' has MRP: $mrp and Price: $price. \n";
    }

    public function __debugInfo()
    {
        return array(
        	'name' => $this->name,
        	'price' => $this->price
        );
    }
}

//create an object of Product class
$product = new Product('Blue Shirt', 1000, 700);
/* OUTPUT: Initializing object - Name: 'Blue Shirt' has MRP: 1000 and Price: 700.  */

//dump the object
var_dump($product);
/* OUTPUT:
object(Product)#1 (2) {
  ["name"]=>
  string(10) "Blue Shirt"
  ["price"]=>
  int(700)
}
*/
?>

The __set_state() Magic Method

The __set_state() magic method gets called when you try to call var_export() method. The var_export() method returns structured information about any variable, property or class instance passed within it.

Example:

<?php
class Product
{
    private $name;
    private $mrp;
    private $price;
    public function __construct($name, $mrp, $price)
    {
        $this->name = $name;
        $this->mrp = $mrp;
        $this->price = $price;
        echo "Initializing object - Name: '$name' has MRP: $mrp and Price: $price. \n";
    }

    public static function __set_state(array $array)
    {
    	$p1 = new Product;
    	$p1->name = $array['name'];
        $p1->mrp = $array['mrp'];
        $p1->price = $array['price'];
        return $p1;
    }
}

//create an object of Product class
$product = new Product('Blue Shirt', 1000, 700);
/* OUTPUT: Initializing object - Name: 'Blue Shirt' has MRP: 1000 and Price: 700.  */

//call the var_export on object
var_export($product);
/* OUTPUT:
Product::__set_state(array(
   'name' => 'Blue Shirt',
   'mrp' => 1000,
   'price' => 700,
))
*/
?>

 

Thank You, Please Share.

Recommended Posts

IMAGE

PHP OOP Interfaces Explained

An Interface allows you to create programs that specifies which methods a class must implement, without defining how those methods are implemented.

IMAGE

PHP OOP Abstract Classes Explained

A PHP class that has minimum one abstract method is called as abstract class and cannot be instantiated by itself.

IMAGE

PHP OOP Traits Explained

Traits in PHP, are a medium of implementing code reuse and allow us to reuse sets of functions freely in several independent classes.