Xtends - Multiple Inheritance

Multiple inheritanhe it's not possible with PHP, only Symfony have an approach called Mixins.

Many frameworks have a Base_controller and all controllers inherit from it. When you have a controller that have common methods, but you want to change few lines of this class, you must to edit it or duplicate it in another class.

With Xtends you can have all common functionality inherit from Base_controller and own functionality, added, overrided or partialy overrided.


How it work's


Normally, your controller (we are using Myclass for this example), extend from a Base_controller:
class Myclass extends Base_controller

Xtends add a intermediate class to allow multiple inheritance:
class Myclass extends Base_loader

In your app/Myclass.php, make a call to xtends_loader method:
public function __construct()
{
    parent::__construct();
   $this->xtends_loader(__CLASS__,__FILE__);
}
                    

This try to load same Myclass.php from another directory (BASEPATH), parse it and load as "MyClass_xtends"

Method that exists in app/Myclass, takes precedence.
Method that not exists in app/Myclass, but exists in base/Myclass, base/Myclas/Method are excuted.
Method that not exists in app/Myclass, neither base/Myclass, but exists in Base_controller, is executed.


In first demo, a normal inheritance, Myclass extends Base_controller...base/Myclass without inheritance
base/Myclass extends from Base_Controller

Second demo is a copy of base/Myclass, located in app/MyClass. Myclass Xtends inheritance
app/MyClass extends from Base_Loader, and also from base/MyClass and also from Base_Controller

Third demo is an empty extend from base/Myclass2, located in app/MyClass2. Myclass2 Xtends inheritance (2)
app/Myclass2 doesn't have any method, inherit all methods from base/MyClass2

You can take a look inside each demo files:

Source of 1st demo
<?php

define
('APPPATH',__DIR__.'/app/');
define('BASEPATH',__DIR__.'/base/');

require 
__DIR__.'/base/Myclass.php';


$myApp = new Myclass();

// Mymethod1 exists in Base_controller, base/myclass and app/myclass, but is returned the last.
echo $myApp->Mymethod1()."<br>";

// Mymethod2 exists in Base_controller and base/myclass and app/myclass, , but is returned the last.
//  In app/myclass 
echo $myApp->Mymethod2()."<br>";

// Mymethod3 exists only in Base_loader
echo $myApp->Mymethod3()."<br>";

// Mymethod4 exists only in Base_controller
echo $myApp->Mymethod4()."<br>";

// Now, another example of multiple inheritance declarations, try to comment the lines:
// 1) public $mynum on app/myclass, reload this page, yuo will see '123'
// 2) public $mynum on base/Base_controller, reload this page, yuo will see '567' (declared in base/myclass)
echo 'Value of $mynum var: '.$myApp->mynum;



Source of 2nd demo
<?php

define
('APPPATH',__DIR__.'/app/');
define('BASEPATH',__DIR__.'/base/');

require 
__DIR__.'/app/Myclass.php';


$myApp = new Myclass();

// Mymethod1 exists in Base_controller, base/myclass and app/myclass, but is returned the last.
echo $myApp->Mymethod1()."<br>";

// Mymethod2 exists in Base_controller and base/myclass and app/myclass, , but is returned the last.
//  In app/myclass 
echo $myApp->Mymethod2()."<br>";

// Mymethod3 exists only in Base_loader
echo $myApp->Mymethod3()."<br>";

// Mymethod4 exists only in Base_controller
echo $myApp->Mymethod4()."<br>";

// Now, another example of multiple inheritance declarations, try to comment the lines:
// 1) public $mynum on app/myclass, reload this page, yuo will see '123'
// 2) public $mynum on base/Base_controller, reload this page, yuo will see '567' (declared in base/myclass)
echo 'Value of $mynum var: '.$myApp->mynum;



Source of app/Myclass.php
<?php

require_once __DIR__.'/../base/Base_loader.php';

class 
Myclass extends Base_Loader
{
    public 
$mynum 890;

    public function 
__construct()
    {
        
parent::__construct();
        
$this->xtends_loader(__CLASS__,__FILE__);
    }
    
    public function 
Mymethod1()
    {
        return 
"MyMethod1 from app/".get_class($this);
    }
    
    public function 
Mymethod2()
    {
        return 
$this->class_xtends->Mymethod2()." <b>example post-adding funtionality</b>";
    }

    public function 
Mymethod3()
    {
        return 
"<b>Example pre-adding functionality:</b> ".parent::Mymethod3();
    }
}


Source of base/Myclass.php
<?php

require_once __DIR__.'/../base/Base_controller.php';

class 
Myclass extends Base_Controller
{
    public 
$mynum 567;

    public function 
__construct()
    {
        
parent::__construct();
    }
    
    public function 
Mymethod1()
    {
        return 
"MyMethod1 from base/".get_class($this)." using base/Myclass";
    }

    public function 
Mymethod2()
    {
        return 
"MyMethod2 from base/".get_class($this)." using base/Myclass";
    }
    
    public function 
Mymethod4()
    {
        return 
"MyMethod4 from base/".get_class($this)." using base/MyClass";
    }
    
}


Source of app/Myclass2.php
<?php

require_once __DIR__.'/../base/Base_loader.php';

class 
Myclass2 extends Base_Loader
{
    public 
$where "We are in app/MyClass2";

    public function 
__construct()
    {
        
parent::__construct();
        
$this->xtends_loader(__CLASS__,__FILE__);
    }
    
}


Source of base/Myclass2.php
<?php

require_once __DIR__.'/../base/Base_controller.php';

class 
Myclass2 extends Base_Controller
{
    public 
$where "We are in base/MyClass2";
    
    public function 
__construct()
    {
        
parent::__construct();
    }
    
    public function 
test1($param1,$param2)
    {
        return 
$this->where.' => '.'Test1 from base/Myclass2, params: '.$param1.'-'.$param2;
    }
}