PHP Magic methods – Magic methods in PHP – Detailed tutorial

Spread the love

What are magic methods in PHP?

PHP Magic methods are a special kind of method defined in OOP PHP,  which gets called automatically when a certain event occurs on an object of a class.

PHP Magic methods names start with double underscores ( __ ). We have already seen such two methods __construct() and __destruct() in our chapter on constructors and destructors in PHP.

In this tutorial, we will see the Magic methods in PHP in detail.


Following are the PHP Magic methods:

__construct() method in PHP Magic methods

__construct is one of the PHP Magic methods that will get called whenever a new instance of a class i.e. an object is created.

It is called a constructor method which is generally used to initialize dependencies or a code that needs to be executed as soon as an object gets created.

<?php
 class Hello
 {
  public $greet;
  
  public function __construct()
  {
   $this->greet = "Hey Hello from PHP.";
  }
 }
 
 $hello = new Hello(); //__construct get called
 echo $hello->greet;
?>



Output:

Hey Hello from PHP.

In the above program as soon as you create a new object “$hello”, __construct() function gets called.

And a property $greet is initialized with the string “Hey Hello from PHP.”.


__destruct() method in PHP Magic methods

__destruct() is another magic method in PHP Magic methods, which gets called automatically when the working of an object gets completed.

This method is called a destructor and it will clear all the resources allocated to the object.

Let’s add the destructor magic method __desctruct() in the above example.

<?php
 class Hello
 {
  public $greet;
  
  public function __construct()
  {
   $this->greet = "Hey Hello from PHP.";
  }
  
  public function __destruct()
  {
   echo "<br>__destruct method is called.";
  }
 }
 
 $hello = new Hello(); //__construct get called
 echo $hello->greet;
 //__destruct method called automatically here.
?>



Output:

Hey Hello from PHP.
__destruct() method is called.

In the above example, as soon as the execution of statements present outside the class are executed, the __destruct() method gets called automatically.


__get() method in PHP Magic methods

__get() magic method in PHP Magic methods, will be called automatically whenever you will try to access the properties of a class.

The specialty of this method is that you can even return the values for non-existent properties, can access the values of protected and private properties.

Though this is not a good way to write for a complete system as it will make code hard to debug, in certain situations, it will be a very valuable function.

Let’s create a simple User class with the only constructor and no properties.

class User
{
 public function __construct()
 {
  echo "In constructor";
 }
 
}
$u = new User;
echo $u->name;



Output:

In constructor
Notice: Undefined property: User::$name in C:xampphtdocsphpclassoopmagicget.php on line 35

If you run the above program you will get a notice – “Notice: Undefined property: User::$name “.

This is because we are trying to access the $name property which is not present in a User class.

Now let’s add the __get() magic method. The __get() method accepts one argument for the name of a property that you are trying to access from outside a class, like __get($propertyName).


Let’s use it in our above program.

class User
{
 public function __construct()
 {
  echo "In constructor<br>";
 }
 
 public function __get($propertyName)
 {
  if(property_exists($this,$propertyName))
  {
   return $this->name;
  }
  else
  {
   return "John Doe";
  }
 }
}
$u = new User;
echo $u->name;



Output:

In constructor
John Doe

Now when PHP executes “echo $u->name;”, __get() method is called automatically and the property “$name” is sent to the __get method as an argument, which is then collected into the “$propertyName” parameter of __get.

Inside __get we are checking whether the property “$name” is present in a class or not. If present then returns the value of $name. Else return the “John Doe”.

In this way, you can send the value for a non-existent property from the __get() method.

Now let’s do the same thing to access the private properties of a class.

class User
{
 private $name;
 private $email;
  
 public function __construct($name,$email)
 {
  $this->name = $name;
  $this->email = $email;
 }
  
 public function __get($propertyName)
 {
  return $this->$propertyName;
 }
 
}
 
$u = new User('John','john@gmail.com');

echo $u->name;
echo "<br>".$u->email;



Output:

John
john@gmail.com

In the above program, we are trying to access the private properties “name” and “email” of a User class.

Without using a __get method you will get a Fatal error to access private properties. But here using the __get method I am returning both “name” and “email”.

Though you can access the private property directly using a property name it is returning from a method.

Let’s see another scenario.

Let’s say the property $name is used all over the program.

Now if something changed at the database backend side and the property “name” is changed to “username“, then, in this case, it would become difficult to change the property to “username” all over the program.

In this case, also you can take the help of the __get method.

class User
{
 private $username;
  
 public function __construct($name)
 {
  $this->name = $name;
 }
  
 public function __get($propertyName)
 {
  if($propertyName == 'name')
  {
   return $this->username;
  }
  
 }
 
}
 
$u = new User('John Doe');

echo $u->name;



Output:

John Doe

In this way, you can manage the accessing of properties at the runtime using the __get magic method in PHP Magic methods.


__set method in PHP Magic methods

The __set magic method in PHP Magic methods is exactly the opposite of the __get method. You can set the private or protected or even non-existent properties of a class using the __set method.

The __set method in PHP Magic methods will automatically be called whenever you try to set the value to any of the existing or non-existing properties of a class.

Hence in the next example, I will try to set the value of a name property that does not exist. And then in the __set method, we will set the value to the private “username” property, like our previous example.


Let’s see the example:

<?php
 class User
 {
  private $username;
  
  public function __set($propertyName, $value)
  {
   if($propertyName == 'name')
   {
    $this->username = $value;
   }
  }
  
  public function __get($propertyName)
  {
   if($propertyName == 'name')
   {
    return $this->username;
   }
   
  }
 }
 
 $t = new User;
 $t->name = 'John Doe';
 
 echo $t->name;
?>

In the above example, I am trying to set the value of a “name” property. But as the “name” is not present in a class PHP will call the __set() magic method.

The __set method has two arguments, first is for the name of a property which you want to set and second is the value of that property.

So, in a __set method, we are setting the value to the existing “username” property.

In this way, you can use a __set magic method in PHP Magic methods for setting values to the properties in a class. __set is one of the most important PHP Magic methods.

Let’s see the next method.


__call() method in PHP Magic methods

The __call() is another magic method in PHP Magic methods which will get called automatically whenever you try to call a method that does not exist in a class, a private, or a protected method.

Let’s see an example:

<?php
 class User
 {
  
 }
 
 $u = new User;
 $u->registerUser();
?>

If you run above the program you will get a fatal error as “Fatal error: Uncaught Error: Call to undefined method User::registerUser() “ because you are trying to call an unknown method “registerUser()” using an object.

Now let’s add __call() magic method. __call() method contains two parameters, first one is a name of a method that does not exist and which you are trying to call, and another parameter is an array of arguments you can pass through that method.

<?php
 class User
 {
  public function __call($methodName, $args)
  {
   echo $methodName." method is not present in a class User.";
   echo "<pre>",print_r($args),"</pre>";
  }
 }
 
 $u = new User;
 $u->registerUser('Param1','Param2','Param3');
?>



The output will be:

registerUser method is not present in a class User.

Array
(
    [0] => Param1
    [1] => Param2
    [2] => Param3
)

As you see in the above example I have used the __call method inside a class User. Now after calling a “registerUser()” method with three parameters then _the _call method is called.

The __call method is collecting two parameters. In the first, a called method name, and in the second the array of those three parameters passed.

In this way, you can either customize the error message for the non-existent method or you can also call another method from inside the __call method.


__callstatic() method in PHP Magic methods

Similar to the __call method in PHP Magic methods, the __callstatic method will also be called automatically whenever you try to call the static method which does not exist in a class.

The __callstatic() method has the same two parameters i.e. the name of a static method and an array of parameters passed.

The __callstatic method should be defined as “static” inside a class.

Let’s see the same example with a static method call.

<?php
 class User
 {
  public static function __callstatic($methodName, $args)
  {
   echo $methodName." static method is not present in a class User.";
   echo "<pre>",print_r($args),"</pre>";
  }
 }
 

 User::registerUser('Param1','Param2','Param3');
?>



The output:

registerUser static method is not present in a class User.
Array
(
    [0] => Param1
    [1] => Param2
    [2] => Param3
)

In the above example, we have defined a static method __callstatic() with the two parameters, the static method name and an array of parameters.

Then we called the static method “registerUser()” using the class name “User”. Hence the __callstatic method gets called.


__isset()

The __isset() is another method in PHP Magic methods that you can use to check whether the private or protected properties of any class have been set or not.

You may have already seen the globally scoped isset() method which is used to check whether the array variable is set or not.

__isset() works the same, whenever you try to check whether the non-existent, protected, or private properties of a class are set or not using isset() method, then __isset() method will get called automatically.

Let’s see an example:

<?php
 class User
 {
  private $username;
  
  public function __isset($propertyName)
  {
   if(isset($this->$propertyName))
   {
    echo $propertyName." is set.";
    return true;
   }
   else
   {
    echo $propertyName." is not set.";
    return false;
   }
  }
  
 }
 

 $user = new User;
 echo isset($user->username);
?>



The output will be:

username is not set.

In the above example, I tried to access the private property “$username” outside the class to check whether it is set or not using “isset()” basic method.

But as the “username” is private property and is not accessible outside the class, PHP calls the magic method __isset() automatically.

Now it’s up to you how you can deal with the property inside an __isset() magic method in PHP Magic methods. In this example, I am checking whether the “username” is set or not and return true or false accordingly.


__unset() method in PHP Magic methods

The __unset() magic method in PHP Magic methods is used to unset the private or protected properties outside of the class.

Whenever you try to unset the private/protected properties using the unset() basic PHP function, outside the class, then the __unset() magic method automatically gets called.

__unset() have one argument i.e. the name of a property to be unset.

Let’s see the example:

<?php
 class User
 {
  private $username = 'john123';
  
  public function getUsername()
  {
   return $this->username;
  }
  
  public function __unset($propertyName)
  {
   if(property_exists($this, $propertyName))
   {
    echo "<br>Username is unset.";
    unset($this->$propertyName);
   }
  }
 }
 
 $u = new User;
 
 echo $u->getUsername();
 
 unset($u->username);
 
 echo $u->getUsername();
?>



The output will be:

john123
Username is unset.
Notice: Undefined property: User::$username in C:xampphtdocsphpclassoopmagicunset.php on line 8

In the above example, I am trying to unset the private property “$username” from outside the class.
Without the __unset() magic method you will get a fatal error as “Fatal error: Uncaught Error: Cannot access private property User::$username “.

But when I have added the __unset method error will be gone and I am now successfully unset the property name inside the __unset() magic method using the basic unset() method in PHP Magic methods.

As you see in the output after unset you try to access the property $username then you will get a notice as an undefined property username.


__tostring()

Another useful magic method in PHP Magic methods is __tostring(). If you just want to echo the object for a sake of that object’s information, you can use __tostring() magic method to return any string you want.

Let’s see an example:

<?php
 class User
 {
  private $name;
  
  public function __construct($name)
  {
   $this->name = $name;
  }
  
 }
 
 $user = new User('John');
 
 echo $user;
 
?>



The output of the above program will be:

Recoverable fatal error: Object of class User could not be converted to string in 
C:xampphtdocsphpclassoopmagictostring.php on line 15

You will get the fatal error because here you are trying to echo the object $user directly.

But now let’s add __tostring method and run the same program.

<?php
 class User
 {
  private $name;
  
  public function __construct($name)
  {
   $this->name = $name;
  }
  
  public function __tostring()
  {
   return get_class($this);
  }
  
 }
 
 $user = new User('John');
 
 echo "Class name of an object is = ".$user;
 
?>



The output:

Class name of an object is = User

As you see, now after adding the __tostring method, I am returning the class name of an object using a function get_class() from the __tostring() method.

And __tostring() method is called as soon as I am trying to echo the object outside the class. So this is a handy method to use whenever you want to return any string by echoing the object.


__sleep()

The __sleep() method in PHP Magic methods gets automatically called whenever you serialize the object. Using __sleep() magic method you can control what you want to serialize and what you don’t want.

Generally, in many classes, you may have some reference to external objects like database connection, like PDO object which is not allowed to be serialized.

You can disconnect such external objects from a class while serializing using the __sleep() method.


For example:

<?php
 class User
 {
  private $dbcon; 
  
  public function __construct()
  {
   $dbcon = new PDO;//Unserializable external PDO object
  }
  public function __sleep()
  {
   $dbcon->disconnect();
  }
  
 }
 $user = new User();
 serialize($user);
?>

In the above example, I am just assuming there is a PDO database object in a class constructor. Now, whenever you use the serialize() method on an object __the sleep() method will automatically get called.

In this example, I am disconnecting the PDO object inside the __sleep() method.

In this way, you can control the things that you want to keep or skip for serializing.


__wakeup() method in PHP Magic methods

The __wakeup() magic method in PHP Magic methods, is exactly the opposite of the __sleep() method. The __wakeup() method will get called once you try to unserialize the serialized object, using unserialize() method.

Let’s see the last example with __wakeup.

<?php
 class User
 {
  private $dbcon; 
  
  public function __construct()
  {
   //$dbcon = new PDO;//Unserializable external PDO object
  }
  public function __sleep()
  {
   echo "In sleep method.";
   //$dbcon->disconnect;
   return [];
  }
  
  public function __wakeup()
  {
   echo "<br>In wakeup method.";
  }
  
 }
 $user = new User();
 $us = serialize($user);

 $user = unserialize($us);
?>

The output will be:

In sleep method.
In wakeup method.

As you see, in the above example whenever you call to unserialize() method on serialized object $us then internally __wakeup() magic method gets called automatically.

Now in the __wakeup() method, you can restore the non-serializable object connections to your class.
Hope you have got a clear picture of __wakeup() in PHP Magic methods.


__invoke() method in PHP Magic methods

Another magic method in a list of Magic methods in PHP is __invoke(). As its name suggests it will invoke something which is nothing but a function.

The __invoke() method will be called automatically whenever you use an object as a function call.

When you use an object variable with parenthesis, and use it as a function __invoke() method will be called.

Let’s see the example:

<?php
 class User
 {
  private $name;
  
  public function __construct($name)
  {
   $this->name = $name;
  }
  
  public function __invoke($param1, $param2)
  {
   return "User object used as a function with two parameters = ".$param1." and ".$param2;
  }
 }
 
 $user = new User('John');
 
 echo $user('Hello','PHP');
?>



The output:

User object used as a function with two parameters = Hello and PHP

In the above example, we have used $user as a function with two parameters like the $user(‘Hello’,’PHP’). 

When you call like this __invoke() method in PHP Magic methods will be called. In this case, we have used two parameters inside __invoke() ‘$param1‘ and ‘$param2‘ to receive the parameter through trough $user(‘Hello’,’PHP’).

You can pass as many parameters as you want.


__autoload()

One of the most useful magic methods in Magic methods in PHP is __autoload(). As its name suggests __autoload() is used to load classes automatically whenever you need them.

Let’s say in your project folder you have three different classes present in three different PHP files, like, User class in user.php, Account class in account.php, and Course class in course.php.

Now, if you want to use the Account and Course class inside a User class, then normally you will use require or include functions.

Like below:

<?php
 require_once('account.php');
 require_once('course.php');
 
 class User
 {
  private $name;
  
  public function __construct($name)
  {
   $this->name = $name;
  }
 }
 
 $user = new User('John');
 $acc = new Account(123);
 $cour = new Course('PHP');
 
?>

In the above program I have used require_once(‘account.php’); and require_once(‘course.php’); to load account.php and course.php files in user.php.

But now, let’s say there are hundreds of files required in a user.php file, then it would not be feasible to use require_once with the name of the required files for each and every file. Then in this case __autoload(), the magic method will be very helpful

The __autoload method in PHP Magic methods will be called automatically as soon as you try to use any class in a file.


Let’s see the updated example.

<?php
 function __autoload($className)
 {
  require_once("$className.php");
 }
 
 class User
 {
  private $name;
  
  public function __construct($name)
  {
   echo "User created.";
   $this->name = $name;
  }
 }
 
 $user = new User('John');
 $acc = new Account(123);
 $cour = new Course('PHP');
 
?>

In the above example, I have used the __autoload($className) magic method above the User class. The __autoload will accept one parameter for the name of a class that you want to use.

Inside __autoload() I have used the require_once() method with the $className variable with the extension “.php“. This will ensure that whenever you use a class that is not present in your current file, then __autoload will be called with that class name as a parameter, and then inside the __autoload, you can call that file using its name.

Hope you have got a clear picture of the __autoload magic method in Magic methods in PHP in this example.


Cloning objects

__clone() in PHP Magic methods.

By default, objects are copied by reference. So whenever you copy one object to another, it’s not actually copied, the other object is just pointing to the object, i.e. having a reference of the copied object.

Hence if you change the first object’s properties, those properties will also get changed in another object.


Example:

<?php
 class User
 {
  public $name;
  
  public function setName($name)
  {
   $this->name = $name;
   
  }
 }
 
 $user1 = new User;
 $user2 = $user1;
 
 $user1->setName('John Doe');
 
 echo "User1 name = ".$user1->name;
 echo "<br>User2 name = ".$user2->name;
 
 //Lets change the name in $user1 object and print both the objects
 $user1->setName('Tony');
 
 echo "<br>User1 name = ".$user1->name;
 echo "<br>User2 name = ".$user2->name;
?>



The output:

User1 name = John Doe
User2 name = John Doe
User1 name = Tony
User2 name = Tony

Such behavior will be sometimes dangerous, as it will change all those objects who copied that object.

Hence to make just a copy of an object to the new variable we have a keyword called “clone”. 

So, instead of just assigning one object to another using “=”, you need to use the “clone” keyword before the object you want to copy.


Updated example:

<?php
 class User
 {
  public $name;
  
  public function setName($name)
  {
   $this->name = $name;
   
  }
 }
 
 $user1 = new User;
 $user2 = clone $user1;
 
 $user1->setName('John Doe');
 
 echo "User1 name = ".$user1->name;
 echo "<br>User2 name = ".$user2->name;
 
 //We need to separatly set the name for user2 now
 $user2->setName('Tony');
 
 echo "<br><br>After setting name of user2";
 echo "<br>User1 name = ".$user1->name;
 echo "<br>User2 name = ".$user2->name;
?>



The output will be:

User1 name = John Doe
User2 name = 

After setting name of user2
User1 name = John Doe
User2 name = Tony

As you see after using “clone“, the name of user2 is not set on its own, as it’s a completely new object with the same structure as user1.

But now let’s say you have another object of an Address class inside a User class. In this case, “clone” won’t work for internal objects and will copy the reference of the internal object.


Let’s see this in the example:

<?php
 class User
 {
  public $name;
  public $address; //Will store Address class object here
  
  public function __construct($name,Address $add)
  {
   $this->name = $name;
   $this->address = $add;
  }
  
 }
 
 class Address
 {
  public $zip;
  
  public function setZip($zip)
  {
   $this->zip = $zip;
  }
  
  public function getZip()
  {
   return $this->zip;
  }
 }
 
 $user = new User('John', new Address);
 
 $clonedUser = clone $user;
 
 //Set the zip of Address for $user object only 
 $user->address->setZip(44227);
 
 echo "Zip of user object = ".$user->address->getZip();
 echo "<br>Zip of clonedUser object = ".$clonedUser->address->getZip();
 
?>

As you see in the above example, we have used the Address class object inside the User class.

After that, we cloned the $user object to the $clonedUser object and set the zip of the Address class through the $user.

But the same zip code is also copied to the $clonedUser object. Now if you change the zip for a $user object it will also reflect in a zip for a $clonedUser object. Hence cloning is not working for internal objects.

To overcome this limitation we have magic method i,e. __clone() in PHP Magic methods.

The __clone() magic method in PHP Magic methods will be called automatically once you use a “clone” keyword to clone the object.

And inside a __clone method, you can make a clone for internal objects as well.


Let’s see this in the same example.

<?php
 class User
 {
  public $name;
  public $address; //Will store Address class object here
  
  public function __construct($name,Address $add)
  {
   $this->name = $name;
   $this->address = $add;
  }
  public function __clone()
  {
   //Cloning the internal Address class object.
   $this->address = clone $this->address;
  }
 }
 
 class Address
 {
  public $zip;
  
  public function setZip($zip)
  {
   $this->zip = $zip;
  }
  
  public function getZip()
  {
   return $this->zip;
  }
 }
 
 $user = new User('John', new Address);
 
 $clonedUser = clone $user;
 
 //Set the zip of Address for $user object only 
 $user->address->setZip(44227);
 
 echo "Zip of user object = ".$user->address->getZip();
 echo "<br>Zip of clonedUser object = ".$clonedUser->address->getZip();
 
 //Set the zip for a clonedUser object
 $clonedUser->address->setZip(112233);
 
 echo "<br><br>After setting name of clonedUser";
 echo "<br>Zip of user object = ".$user->address->getZip();
 echo "<br>Zip of clonedUser object = ".$clonedUser->address->getZip();
 
?>



The output will be:

Zip of user object = 44227
Zip of clonedUser object = 

After setting name of clonedUser
Zip of user object = 44227
Zip of clonedUser object = 112233

After using the __clone method we have used the “$this->address = clone $this->address;” statement to clone the internal object of the Address class.

Hence now the internal address object is not copied by reference. Instead, you need to set the new value for a zip of $clonedUser’s address object, as you see in the output.

In this way, you can use a whole lot of PHP Magic methods in your object-oriented PHP applications.

So, this is the whole big chapter about the PHP Magic methods in object-oriented programming.

If you have any doubts or queries please comment below. I will try to solve them as soon as possible.

And if you find this chapter helpful please share it with your friends and colleagues to spread the knowledge about PHP Magic methods.

You can also look into the official documentation about PHP magic methods.


Spread the love

Leave a Comment