Note: I'm migrating from gonzalo123.com to here. When I finish I'll swap the DNS to here. The "official" blog will be always gonzalo123.com

      Multiple inheritance with PHP and Traits

      Multiple inheritance isn’t allowed in PHP. With Python we can do things like that:

      class ClassName(Base1, Base2):
          ....
      

      That’s no possible with PHP (in Java is not possible either), but today we can do something similar (is not the exactly the same) with Traits. Let me explain that: Instead of classes we can create Traits:

      <?php
      trait Base1
      {
          public function hello1($name)
          {
              return "Hello1 {$name}";
          }
      } 
       
      trait Base2
      {
          public function hello2($name)
          {
              return "Hello2 {$name}";
          }
      } 
      

      And now we can use those traits (instead of to extend multiple classes)

      <?php
      class ClassName
      {
          use Base1, Base2;
      } 
      

      The main reason because multiple inheritance isn’t allowed in PHP, Java and another languages is is due to the collisions. If we extends from two classes with the same method, which is the good one? Python solves this problem with a easy solution: The first one is the good one:

      class Base1:
          def hello1(self, name):
              return "Hello1 " + name
       
      class Base2:
          def hello1(self, name):
              return "Hello2 " + name
       
      class ClassName(Base1, Base2):
          pass
      c = ClassName()
      print c.hello1("Gonzalo")
      

      Will output “Hello1 Gonzalo” but if change the inheritance order to:

      class ClassName(Base2, Base1):
          pass
      

      The output will be “Hello2 Gonzalo”

      Traits in PHP doesn’t solve the problem “out of the box”. If we use the following script:

      <?php
      trait Base1
      {
          public function hello1($name)
          {
              return "Hello1 {$name}";
          }
      }
       
      trait Base2
      {
          public function hello1($name)
          {
              return "Hello2 {$name}";
          }
      }
       
      class ClassName
      {
          use Base1, Base2;
      }
       
      $class = new ClassName();
      echo $class->hello1("Gonzalo");
      

      Our script will throw a Fatal error:

      PHP Fatal error: Trait method hello1 has not been applied, because there are collisions with other trait methods on ClassName on line 23

      If we want to avoid collisions, we need to describe explicitly what function we will use. It’s not difficult:

      <?php
      trait Base1
      {
          public function hello1($name)
          {
              return "Hello1 {$name}";
          }
      }
       
      trait Base2
      {
          public function hello1($name)
          {
              return "Hello2 {$name}";
          }
      }
       
      class ClassName
      {
          use Base1, Base2 {
              Base1::hello1 insteadof Base2;
          }
      }
       
      $class = new ClassName();
      echo $class->hello1("Gonzalo");
      

      comments powered by Disqus