Question

Si j'ai plusieurs classes avec des fonctions dont j'ai besoin mais que je souhaite stocker séparément pour l'organisation, puis-je étendre une classe pour avoir les deux?

c'est à dire class a extends b extends c

Edit: Je sais comment prolonger les classes une à la fois, mais je recherche une méthode pour étendre instantanément une classe en utilisant plusieurs classes de base - Afaik, vous ne pouvez pas le faire en PHP, mais il devrait y avoir des moyens de contourner sans recourir à class c extends b, class b extends a

Était-ce utile?

La solution

Répondre à votre modification:

Si vous voulez vraiment simuler l'héritage multiple, vous pouvez utiliser la fonction magique __Call ().

C'est moche bien que cela fonctionne du point de vue de l'utilisateur de la classe A:

class B {
    public function method_from_b($s) {
        echo $s;
    }
}

class C {
    public function method_from_c($s) {
        echo $s;
    }
}

class A extends B
{
  private $c;

  public function __construct()
  {
    $this->c = new C;
  }

  // fake "extends C" using magic function
  public function __call($method, $args)
  {
    $this->c->$method($args[0]);
  }
}


$a = new A;
$a->method_from_b("abc");
$a->method_from_c("def");

Imprime "ABCDEF"

Autres conseils

Vous ne pouvez pas avoir une classe qui prolonge deux classes de base. Vous ne pouviez pas avoir.

// this is NOT allowed (for all you google speeders)
Matron extends Nurse, HumanEntity

Vous pourriez cependant avoir une hiérarchie comme suit ...

Matron extends Nurse    
Consultant extends Doctor

Nurse extends HumanEntity
Doctor extends HumanEntity

HumanEntity extends DatabaseTable
DatabaseTable extends AbstractTable

etc.

Vous pouvez utiliser des traits, qui, espérons-le, seront disponibles auprès de PHP 5.4.

Les traits sont un mécanisme de réutilisation de code dans les langages d'héritage unique tels que PHP. Un trait vise à réduire certaines limites de l'héritage unique en permettant à un développeur de réutiliser librement les ensembles de méthodes dans plusieurs classes indépendantes vivant dans différentes hiérarchies de classe. La sémantique de la combinaison des traits et des classes est définie d'une manière, ce qui réduit la complexité et évite les problèmes typiques associés à l'héritage multiple et aux mélanges.

Ils sont reconnus pour leur potentiel pour soutenir une meilleure composition et une meilleure réutilisation, d'où leur intégration dans des versions plus récentes de langues telles que Perl 6, Squeak, Scala, Slate et Fortress. Des traits ont également été portés vers Java et C #.

Plus d'information: https://wiki.php.net/rfc/Traits

Les classes ne sont pas censées être de seulement des collections de méthodes. Une classe est censée représenter un concept abstrait, à la fois avec l'état (champs) et le comportement (méthodes) qui change l'état. L'utilisation de l'héritage juste pour obtenir un comportement souhaité ressemble à une mauvaise conception OO, et exactement la raison pour laquelle de nombreuses langues interdisent l'héritage multiple: afin d'éviter "l'héritage des spaghetti", c'est-à-dire en étendant 3 classes car chacun a une méthode dont vous avez besoin et vous retrouvant avec Une classe qui hérite de 100 et 20 champs de méthode, mais n'en utilise que 5.

Il y a des plans pour ajouter des mix-ins bientôt, je crois.

Mais jusque-là, optez pour la réponse acceptée. Vous pouvez résumer cela un peu pour faire une classe "extensible":

class Extendable{
  private $extender=array();

  public function addExtender(Extender $obj){
    $this->extenders[] = $obj;
    $obj->setExtendee($this);
  }

  public function __call($name, $params){
    foreach($this->extenders as $extender){
       //do reflection to see if extender has this method with this argument count
       if (method_exists($extender, $name)){
          return call_user_func_array(array($extender, $name), $params);
       }
    }
  }
}


$foo = new Extendable();
$foo->addExtender(new OtherClass());
$foo->other_class_method();

Notez que dans ce modèle "AutreClass" arrive à «connaître» sur $ foo. AutreClass doit avoir une fonction publique appelée "sextendee" pour mettre en place cette relation. Ensuite, si ses méthodes sont invoquées à partir de $ foo, il peut accéder à $ foo en interne. Il n'aura cependant pas accès à des méthodes / variables privées / protégées comme le ferait une véritable classe étendue.

La réponse actuellement acceptée par @franck fonctionnera mais ce n'est en fait pas un héritage multiple mais une instance d'enfant de classe définie hors de portée, il y a également le __call() sténographie - envisagez d'utiliser juste $this->childInstance->method(args) Partout où vous avez besoin de la méthode de classe EXTERNALCLASS dans la classe "étendue".

Réponse exacte

Non, vous ne pouvez pas, respectivement, pas vraiment, comme manuel extends mot-clé dit:

Une classe étendue dépend toujours d'une seule classe de base, c'est-à-dire que l'héritage multiple n'est pas pris en charge.

Réponse réelle

Cependant, comme @ADAM l'a suggéré correctement, cela ne vous interdit pas d'utiliser un héritage hiérarchique multiple.

Vous pouvez prolonger une classe, avec un autre et un autre avec un autre et ainsi de suite ...

Un exemple si simple à ce sujet serait:

class firstInheritance{}
class secondInheritance extends firstInheritance{}
class someFinalClass extends secondInheritance{}
//...and so on...

Note importante

Comme vous l'avez peut-être remarqué, Vous ne pouvez faire de la hiérarchie multiple (2+) que si vous avez le contrôle sur toutes les classes incluses dans le processus - Cela signifie que vous ne pouvez pas appliquer cette solution, par exemple avec des classes intégrées ou avec des classes que vous ne pouvez tout simplement pas modifier - si vous voulez le faire, vous vous retrouvez avec la solution @Franck - Instances enfants.

... et enfin exemple avec une certaine sortie:

class A{
  function a_hi(){
    echo "I am a of A".PHP_EOL."<br>".PHP_EOL;  
  }
}

class B extends A{
  function b_hi(){
    echo "I am b of B".PHP_EOL."<br>".PHP_EOL;  
  }
}

class C extends B{
  function c_hi(){
    echo "I am c of C".PHP_EOL."<br>".PHP_EOL;  
  }
}

$myTestInstance = new C();

$myTestInstance->a_hi();
$myTestInstance->b_hi();
$myTestInstance->c_hi();

Quelles sorties

I am a of A 
I am b of B 
I am c of C 

Utilisez des traits comme classes de base. Ensuite, utilisez-les dans une classe parent. L'étendez-le.

trait business{
  function sell(){

  }

  function buy(){

  }

  function collectMoney(){
  }

}

trait human{

   function think(){

   }

   function speak(){

   }

}

class BusinessPerson{
  use business;
  use human;
  // If you have more traits bring more
}


class BusinessWoman extends BusinessPerson{

   function getPregnant(){

   }

}


$bw = new BusinessWoman();
$bw ->speak();
$bw->getPregnant();

Voir maintenant Business Woman hérité logiquement les affaires et l'humain;

<?php
// what if we want to extend more than one class?

abstract class ExtensionBridge
{
    // array containing all the extended classes
    private $_exts = array();
    public $_this;

    function __construct() {$_this = $this;}

    public function addExt($object)
    {
        $this->_exts[]=$object;
    }

    public function __get($varname)
    {
        foreach($this->_exts as $ext)
        {
            if(property_exists($ext,$varname))
            return $ext->$varname;
        }
    }

    public function __call($method,$args)
    {
        foreach($this->_exts as $ext)
        {
            if(method_exists($ext,$method))
            return call_user_method_array($method,$ext,$args);
        }
        throw new Exception("This Method {$method} doesn't exists");
    }


}

class Ext1
{
    private $name="";
    private $id="";
    public function setID($id){$this->id = $id;}
    public function setName($name){$this->name = $name;}
    public function getID(){return $this->id;}
    public function getName(){return $this->name;}
}

class Ext2
{
    private $address="";
    private $country="";
    public function setAddress($address){$this->address = $address;}
    public function setCountry($country){$this->country = $country;}
    public function getAddress(){return $this->address;}
    public function getCountry(){return $this->country;}
}

class Extender extends ExtensionBridge
{
    function __construct()
    {
        parent::addExt(new Ext1());
        parent::addExt(new Ext2());
    }

    public function __toString()
    {
        return $this->getName().', from: '.$this->getCountry();
    }
}

$o = new Extender();
$o->setName("Mahdi");
$o->setCountry("Al-Ahwaz");
echo $o;
?>

J'ai lu plusieurs articles décourageant l'héritage dans les projets (par opposition aux bibliothèques / cadres) et j'encourage à programmer des interfaces Agaisnt, non contre les implémentations.
Ils préconisent également OO par composition: si vous avez besoin des fonctions en classe A et B, faites C ayant des membres / champs de ce type:

class C
{
    private $a, $b;

    public function __construct($x, $y)
    {
        $this->a = new A(42, $x);
        $this->b = new B($y);
    }

    protected function DoSomething()
    {
        $this->a->Act();
        $this->b->Do();
    }
}

L'héritage multiple semble fonctionner au niveau de l'interface. J'ai fait un test sur PHP 5.6.1.

Voici un code de travail:

<?php


interface Animal
{
    public function sayHello();
}


interface HairyThing
{
    public function plush();
}

interface Dog extends Animal, HairyThing
{
    public function bark();
}


class Puppy implements Dog
{
    public function bark()
    {
        echo "ouaf";
    }

    public function sayHello()
    {
        echo "hello";
    }

    public function plush()
    {
        echo "plush";
    }


}


echo PHP_VERSION; // 5.6.1
$o = new Puppy();
$o->bark();
$o->plush();
$o->sayHello(); // displays: 5.6.16ouafplushhello

Je ne pensais pas que c'était possible, mais je suis tombé sur le code source SwiftMailer, dans la classe Swift_Transport_iobuffer, qui a la définition suivante:

interface Swift_Transport_IoBuffer extends Swift_InputByteStream, Swift_OutputByteStream

Je n'ai pas encore joué avec, mais je pensais qu'il pourrait être intéressant de partager.

Je viens de résoudre mon problème "multiple héritage" avec:

class Session {
    public $username;
}

class MyServiceResponsetype {
    protected $only_avaliable_in_response;
}

class SessionResponse extends MyServiceResponsetype {
    /** has shared $only_avaliable_in_response */

    public $session;

    public function __construct(Session $session) {
      $this->session = $session;
    }

}

De cette façon, j'ai le pouvoir de manipuler la session à l'intérieur d'une superponse de session qui étend MyServiceResponseType qui peut toujours gérer la session par elle-même.

Vous pouvez le faire en utilisant des traits en PHP qui ont annoncé à partir de PHP 5.4

Voici un tutoriel rapide pour vous, http://culttt.com/2014/06/25/PHP-TRraits/

PHP ne prend pas encore en charge l'héritage de la classe multiple, il prend cependant en charge l'héritage d'interface multiple.

Voir http://www.hudzilla.org/php/6_17_0.php pour quelques exemples.

PHP n'autorise pas l'héritage multiple, mais vous pouvez faire avec la mise en œuvre de plusieurs interfaces. Si la mise en œuvre est "lourde" implémentation squelettique pour chaque interface dans une classe séparée. Ensuite vous pouvez Déléguer toute la classe d'interface à ces implémentations squelettiques passant par confinement des objets.

Ne sachant pas exactement ce que vous essayez de réaliser, je vous suggère de rechercher la possibilité de repenser votre application pour utiliser la composition plutôt que l'héritage dans ce cas.

Always good idea is to make parent class, with functions ... i.e. add this all functionality to parent.

And "move" all classes that use this hierarchically down. I need - rewrite functions, which are specific.

If you want to check if a function is public see this topic : https://stackoverflow.com/a/4160928/2226755

And use call_user_func_array(...) method for many or not arguments.

Like this :

class B {
    public function method_from_b($s) {
        echo $s;
    }
}

class C {
    public function method_from_c($l, $l1, $l2) {
        echo $l.$l1.$l2;
    }
}

class A extends B {
    private $c;

    public function __construct() {
        $this->c = new C;
    }

    public function __call($method, $args) {
        if (method_exists($this->c, $method)) {
            $reflection = new ReflectionMethod($this->c, $method);
            if (!$reflection->isPublic()) {
                throw new RuntimeException("Call to not public method ".get_class($this)."::$method()");
            }

            return call_user_func_array(array($this->c, $method), $args);
        } else {
            throw new RuntimeException("Call to undefined method ".get_class($this)."::$method()");
        }
    }
}


$a = new A;
$a->method_from_b("abc");
$a->method_from_c("d", "e", "f");

One of the problems of PHP as a programming language is the fact that you can only have single inheritance. This means a class can only inherit from one other class.

However, a lot of the time it would be beneficial to inherit from multiple classes. For example, it might be desirable to inherit methods from a couple of different classes in order to prevent code duplication.

This problem can lead to class that has a long family history of inheritance which often does not make sense.

In PHP 5.4 a new feature of the language was added known as Traits. A Trait is kind of like a Mixin in that it allows you to mix Trait classes into an existing class. This means you can reduce code duplication and get the benefits whilst avoiding the problems of multiple inheritance.

Traits

class A extends B {}

class B extends C {}

Then A has extended both B and C

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top