Backend Development

PHP OOP With Magic Methods

In this tutorial we will learn about exclusive topic in php oop which is Magic Methods. Any class that you create in php has some built in methods. Those methods are special methods that allow you to react to certain events during class life cycle.

Magic methods begin with __ and any one of us already came across a number of these methods in classes specially the two important __construct() and __destruct() so let’s discover these.

 

__construct() and __destruct()

The most common of these is the __construct() and __destruct(). __construct()  is called automatically when you create a new instance of the class but __destruct() is called when the object execution life cycle is terminated or destroyed.

 

__construct can be used to initialize variables and in the context of dependency injection but __destruct() can be used to do things like garbage memory resources or unsetting values that already created by the constructor. One real world examples of these is to open and close a database connection.

 

Let’s see it in action:

<?php
class Post
{
    protected $title;
    protected $description;

    public function __construct($title, $description)
    {
        $this->title = $title;
        $this->description = $description;

        $this->log('class started!');
    }

     public function getTitle()
     {
         return $this->title;
     }

     public function getDescription()
     {
         return $this->description;
     }

    private function log($msg)
    {
       echo $msg . "<br/>";
    } 

     public function __destruct()
     {
         $this->log('class terminated!');
     }
}

$post = new Post('new post', 'This is a new blog post');

// Will output

class started!
class terminated!

In the example above note that when we create a new instance of class Post it called the two magic methods __construct() and __destruct().

 

__get() and __set()

Usually in php there are certain circumstances when you need to access a property directly by its name but because the property you want to access declared as protected or private it will cause error so to access it you have to implement  __get() and __set().

<?php
class Post
{
    protected $title;
    protected $description;

    public function __construct($title, $description)
    {
        $this->title = $title;
        $this->description = $description;
    }

    public function __get($property)
    {
         if (property_exists($this, $property)) {  
            return $this->$property;  
         }  
    }
}

$post = new Post('post title', 'This is a new blog post');

echo $post->title . "<br/>";

echo $post->description;


// Will output
// post title
// This is a new blog post

The __get() method will be called  automatically for properties that are not public properties. The __get() method accepts the name of the property you were looking for as an argument. In the code above, first I check to see if the property exists on the current object. If it does, I can return it dynamically from the object.

 

If you try to set a property that is not accessible, the __set() magic method will be called. This method takes the property you were attempting to access and the value you were trying to set as two arguments.

<?php
public function __set($property, $value)  
{  
    if (property_exists($this, $property)) {  
         $this->$property = $value;  
    }  
}


$post->title = 'Setting up new title';  
echo $post->title; // 'Setting up new title'  

In these two examples I’ve shown how you can get or set properties on an object that are not set to public. Always try to use these methods in your own projects instead of creating custom getters or setters.

__isset() and __unset()

You already encountered the isset() function in a lot of scripts when working with arrays to check if specific key is exist. You can also use this function on objects to see if a publicly accessible property has been set.

If you attempt to use this function to check the presence of a property that isn’t publicly accessible, you can use the __isset() magic method to respond:

<?php

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

isset($post->title); // true  

From the above code true will be returned because when you call isset() on the title property it will call __isset() behind the scenes and return true.

 

Similar to the isset() function, the unset() function is commonly used when working with arrays. Again, as with the isset() function, you can also run it on an object to unset public properties. If the property you are trying to unset is not public, the __unset() method will will be triggered and allow you to implement it:

<?php
public function __unset($property)  
{  
     unset($this->$property);  
}  

 

__toString()

The __toString() allows you to return a string representation of an object. If you work with one of the most common frameworks like Laravel or Yii you will encounter it in the Model classes.

<?php

public function __toString()  
{  
     return $this->title . '<br/>' . $this->description;  
}

$post = new Post('new title', 'new description');  
echo $post; 

// new title
// new description  

This means whenever you try to cast the object as a string, such as trying to use echo, the object will be returned however you define it in the __toString() method.

 

 

__sleep() and __wakeup()

The serialize() function is a pretty common way to store a representation of an object. For example, if you wanted to store an object in the database, first you would serialize it, store it, and then when you wanted it again you would unserialize it.

The __sleep() method allows you to define which properties of the object should be serialized as you probably don’t want to serialize any kind of external object that might not be relevant when you unserialize the object.

<?php
public function __sleep()  
{  
     return array('title', 'description');  
}  

$post = new Post('new post', 'This is a new blog post'); 

echo serialize($post);

// O:4:"Post":2:{s:8:"*title";s:8:"new post";s:14:"*description";s:23:"This is a new blog post";}

When it comes to unserializing the object, or recovering it we use __wakeup() method.

__call()

The __call() method will be called when you try to access a method that is not publicly accessible on the object. For example you might have an array of data on the object that you want to mutate before returning:

<?php
class Post
{
    protected $title;
    protected $description;

    public function __construct($title, $description)
    {
        $this->title = $title;
        $this->description = $description;
    }

     private function getTitle()
     {
         return $this->title;
     }

     private function getDescription()
     {
         return $this->description;
     }
      
     public function __call($method, $parameters)  
     {  
        if (method_exists($this, $method))  
        {  
            return call_user_func_array(array($this, $method), $parameters);  
        }  
     }  
}

$post = new Post('new private post', 'This is a new blog post');

echo $post->getTitle()."<br/>";    

echo $post->getDescription();

// new private post
// This is a new blog post

In the above code method getTitle() and getDescription() is defined private however because we implement __call() it will be called.

 

__callStatic()

Like the __call() the __callStatic() magic method used when you attempt to access a non public method, but the difference between them is that when you call the method in static scope for example Class::method(). Some frameworks such as laravel uses this approach to call facade methods such as Cache::get().

class Cache
{
     private static $store = [];
     
     private function set($key, $value)
     {
         self::$store[$key] = $value;
     }
   
     private function get($key)
     {
           if(isset(self::$store[$key])) {
                return self::$store[$key];
           }
         
           return null;
     }

     public static function __callStatic($method, $parameters)
     {
         if(method_exists(__CLASS__, $method))
         {
               return self::$method(...$parameters);
         }
     }
}

Cache::set('id', 1);
Cache::set('name', 'john deo');

echo Cache::get('id') . '<br/>';
echo Cache::get('name');

 

 

__clone()

When you make a copy of an object in PHP, it is still linked to the original object. This means if you make a change to the original object, your copied object will also be changed:

<?php
$car1 = new stdClass;  
$car2 = $car1;

$car2->name = "BMW";  
$car1->name = "Kia";

echo $car1->name; // Kia  
echo $car2->name; // Kia  

This is because when you copy an object in PHP, it is “passed as a reference”, meaning, it maintains a link to the original object However if you to create to distinct objects you have to implement __clone():

<?php
$car1 = new stdClass;  
$car2 = clone $car1;

$car2->name = "BMW";  
$car1->name = "Kia";

echo $car1->name; // Kia  
echo $car2->name; // BMW  

 

__invoke()

The __invoke() magic method allows you to use an object as if it were a function:

<?php
function callClosure(Callable $func) {
  $func();
  return "called";
}
 
class Post {
  public function __invoke() {
    echo "Post";
  }
}
 
$post = new Post();
echo callClosure($post); // Post called

 

conclusion

In this tutorial you learned about php magic methods and how to use them. Many frameworks make use of magic methods as it provides many benefits and away of clean code and maintainability.

0 0 votes
Article Rating

What's your reaction?

Excited
1
Happy
0
Not Sure
0
Confused
0

You may also like

Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments