multiple inheritance in php

Multiple Inheritance in PHP using Trait

What is a trait?

PHP 5.4.0 was coming with one amazing feature. In an earlier version of PHP, there is no any method to implement the multiple inheritance in PHP. PHP 5.4.0 comes with a trait.
traits in PHP – provide a mechanism which will allow us to reuse the code in single inheritance languages such as PHP.

Why use traits?

The main purpose of Object Oriented Programming to minimise the duplicate code and increase the reusability of the code. PHP has a few limitations such as no feature of multiple inheritances. PHP 5.4.0 comes with traits, which will fulfil this limitation. The Trait behaves like an abstract class. It can not be instantiated on its own.

Before Starting on Trait let’s have some basic idea of inheritance and multiple inheritances.

Inheritance:

It’s one of the biggest concepts of PHP which will allow us to use the property(functions) of one class into another. By using it we can reuse the code.

Single Inheritance:

In Single Inheritance one derived class inherits from only one base class. It is the simplest form of Inheritance.

A Super Class
|
B Sub Class

Multiple Inheritance in PHP :

In Multiple Inheritance derived class may have two or more than two base classes.

A     B
|      |
——–
|
C

Now we again come on Trait.

How to use Trait?

Traits can be initialized with the keyword trait. To understand Trait in detail let’s see an example.

Syntax:

trait traitName
{
    public function functionName($params)
    {
         // Code
    }
}

Code:

trait Base
{
    public function say($word)
    {
        echo "Say".$word;
    }
}
class sayHello
{
    use Base;
}
class sayWorld
{
    use Base;
}
$objSayHello = new sayHello();
$objSayHello->say("Hello!!!<br>");
$objSayWorld = new sayWorld();
$objSayWorld->say("World!!!");

Output:

Say Hello!!!
Say World!!!

As you can see from the example above, We have one Trait called “Base” and two classes “sayHello and sayWorld”. Base contain one function called say(). Both of the classes uses Base.
Both objSayHello and objSayWorld objects have the say() method available despite not having that method defined. A Trait provides a way to “reuse” code during run time. We can say that Trait provides a way to “copy and paste” the code. So by using the class objects we can use functions which are defined in Trait.

Class function override with trait:

Code:

class BaseClass
{
     public function sayHelloWorld()
     {
         echo 'Hello ';
     }
}
trait SayWorld
{
    public function sayHelloWorld()
    {
        parent::sayHelloWorld();
        echo 'World!';
    }
}
class derivedClass extends BaseClass
{
    use SayWorld;
}
$obj = new derivedClass();
$obj->sayHelloWorld();

Output:

Hello World

Using multiple traits:

We can have multiple traits in a class. The class which contain multiple traits we can say that we have multiple inheritances for that specific class. Let’s see this for example.
So the class which contain multiple traits will have all the functions available in both traits.

Code:

trait hello
{
    function sayHello() { echo "Hello"; } // method1
}
trait world
{
    function sayWorld() { echo "World!!!"; } // method2
}
class HelloWorld
{
   // now using more than one trait
   use hello, world;
}
$obj= new HelloWorld();
$obj->sayHello(); // Print : sayHello
$obj->sayWorld(); // Print : sayWorld

Output:

Hello World!!!

Traits inside another Trait:

Code:

trait first_trait
{
    function methodOne() { echo "method1"; }
}
trait second_trait
{
   use first_trait;
   function methodSecond() { echo "method2"; }
}
class first_class
{
   // now using
   use second_trait;
}
$obj= new first_class();
$obj->methodOne(); // Print : methodOne
$obj->methodSecond(); // Print : methodSecond

Output:

method1 method2

How are traits differed to the interface?

By seeing the syntax and use, it looks like traits and interface are same, however, there is one difference between them. An interface can say that this object is able to do this thing whereas a Trait is giving the object the ability to do the thing.

Code:

// Interface
interface computer
{
    public function copy();
    public function paster();
}
// Trait
trait CPU
{
    public function paste($item)
    {
       // Paste this item
    }
}
// Class
class User implements first_interface
{
    use CPU;
    public function copy()
    {
      //
    }
}
$user = new User;
if($user instanceOf cpu)
{
     $user->paste('hello world');
}

Here we can see “computer” is an interface that states that the User object is able to use copy() and paste().

The “CPU” Trait implements the paste() method and the copy() method is implemented in the User class.

So as you can see we could hint the User object to see if it is CPU (it implements the computer interface), whilst the Trait defines a reusable method that we can then mix into other similar classes.

How to use an abstract method in Trait?

We can use an abstract method in traits. If we declared an abstract method in traits, the class  which use that trait must have to implement that method. This is the same concept as the abstract class and abstract method.

Code:

trait first_trait
{
    function methodOne() { echo "method1"; }
    // any class which use this trait must
    // have to implement below method.
    abstract public function methodSecond();
}
class methodOne
{
    use first_trait;
   function methodSecond()
   {
       /* Code Here */
   }
}

Conflicts in Traits:

Suppose you have created two different traits which contain same function name. In this particular case you will get an error like “Fatal error: Cannot redeclare function error”.

Code:

trait RegisterUser
{
   function login()
   {
     echo "RegisterUser Login";
   }
}
trait Admin
{
   function login()
  {
   echo "Admin Login";
  }
}
class Users
{
   use RegisterUser, Admin;
}
$obj = new Users();
// Output: From First Trait
$obj->login();

How to avoid this error?

The trait has one operator which will help us to avoid this kind of scenario. This can be done using insteadof operator.

Syntax:

class className
{
   use first_trait, second_trait
   {
      // This class will now call the method
      // first function from first_trait only
      first_trait::first_function insteadof second_trait;
   }
}

Let’s see an example for this.

Code:

trait RegisterUser
{
    function login()
    {
       echo "RegisterUser Login";
    }
}
trait Admin
{
    function login()
    {
       echo "Admin Login";
    }
}
class Users
{
    use RegisterUser, Admins
    {
       // This class will now call the method
       // first function from first_trait only
       RegisterUser::login insteadof Admin;
    }
}
$obj = new Users();
// Output: From First Trait
$obj->login();

So like this, we can remove the conflicts of Traits. Suppose I want to use the method from the both trait then what can we do ?
So for this kind of case, we can use as operator for rescue. This operator maintains the aliasing.

Syntax:

class className
{
    use first_trait, second_trait
    {
       // This class will now call the method
       // first function from first_trait only
       first_trait::first_function insteadof second_trait;
       // first_function of second_traits can be
       // accessed with second_function
       second_trait::first_function as second_function;
    }
}

Code:

trait RegisterUser
{
   function login()
   {
      echo "RegisterUser Login";
   }
}
trait Admin
{
   function login()
   {
      echo "Admin Login";
   }
}
class Users
{
    use RegisterUser, Admins
    {
       RegisterUser::login insteadof Admin;
       Admin::login as login;
    }
}
$obj = new Users();
// Output: From First Trait
$obj->login();

Important points of trait:

Multiple Inheritance in PHP - Notes

 
How to add external file code in your current file. To know this click here.

2 thoughts on “Multiple Inheritance in PHP using Trait

  1. Hello,

    There is error in code for “Using multiple traits”,
    Correct code is as below :

    trait hello
    {
    function sayHello() { echo “Hello”; } // method1
    }
    trait world
    {
    function sayWorld() { echo “World!!!”; } // method2
    }

    class HelloWorld
    {
    // now using more than one trait
    use hello, world;
    }

    $obj= new HelloWorld();
    $obj->sayHello(); // Print : sayHello
    $obj->sayWorld(); // Print : sayWorld

Leave a Reply