Pergunta

Se eu tiver várias classes com funções que eu preciso, mas deseja armazenar separadamente para a organização, posso estender uma classe para ter os dois?

i.e. class a extends b extends c

editar:Eu sei como estender classes, uma de cada vez, mas eu estou procurando por um método instantaneamente estender uma classe com várias classes base - AFAIK você não pode fazer isso em PHP, mas deve haver maneiras de contornar isso sem recorrer à class c extends b, class b extends a

Foi útil?

Solução

Respondendo à sua edição:

Se você realmente deseja fingir herança múltipla, pode usar a função mágica __call ().

Isso é feio, embora funcione do ponto de vista do usuário da 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"

Outras dicas

Você não pode ter uma classe que estende duas classes base. Você não poderia ter.

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

No entanto, você pode ter uma hierarquia da seguinte maneira ...

Matron extends Nurse    
Consultant extends Doctor

Nurse extends HumanEntity
Doctor extends HumanEntity

HumanEntity extends DatabaseTable
DatabaseTable extends AbstractTable

e assim por diante.

Você pode usar características, que, esperançosamente, estarão disponíveis no Php 5.4.

Traits é um mecanismo para reutilização de código em idiomas de herança única, como o PHP. Uma característica visa reduzir algumas limitações de herança única, permitindo que um desenvolvedor reutilize conjuntos de métodos livremente em várias classes independentes que vivem em diferentes hierarquias de classe. A semântica da combinação de características e classes é definida de uma maneira, o que reduz a complexidade e evita os problemas típicos associados à herança e mixins múltiplas.

Eles são reconhecidos por seu potencial em apoiar uma melhor composição e reutilização, daí sua integração em versões mais recentes de idiomas como Perl 6, Squeak, Scala, Slate e Fortress. As características também foram portadas para Java e C#.

Mais Informações: https://wiki.php.net/rfc/traits

As aulas não devem ser apenas coleções de métodos. Uma classe deve representar um conceito abstrato, com estado (campos) e comportamento (métodos) que mudam o estado. Usando a herança apenas para obter um comportamento desejado soa como um design ruim de oo e exatamente a razão pela qual muitos idiomas não perseguem a herança múltipla: para evitar "herança de espaguete", ou seja, estendendo 3 aulas porque cada um tem um método que você precisa e acabar Uma aula que herda o método 100 e 20 campos, mas só usa 5 deles.

Há planos para adicionar mix-ins em breve, creio eu.

Mas até então, vá com o aceite de resposta.Você pode abstrato que fora um pouco para fazer um "extensível" classe:

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();

Note-se que neste modelo de "OtherClass" chega ao "saber" de cerca de us $foo.OtherClass precisa ter uma função pública denominada "setExtendee" para definir esta relação.Então, se os métodos são invocados a partir de $foo, pode aceder $foo internamente.Ele não, no entanto, ter acesso a qualquer private/protected/métodos variáveis como um verdadeiro estendido classe.

Atualmente aceita a resposta de @franck funcionará, mas não é de fato uma herança múltipla, mas uma instância infantil de classe definida fora do escopo, também existe o __call() abreviação - considere usar apenas $this->childInstance->method(args) Em qualquer lugar que você precise do método da classe ExternalClass na classe "estendida".

Resposta exata

Não, você não pode, respectivamente, não, como manual de extends palavra -chave diz:

Uma classe estendida sempre depende de uma única classe base, ou seja, a herança múltipla não é suportada.

Resposta real

No entanto, como @adam sugeriu corretamente, isso não proíbe você usar várias herança hierárquica.

Você pode estender uma aula, com outra e outra com outra e assim por diante ...

Exemplo tão simples sobre isso seria:

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

Nota importante

Como você deve ter notado, Você só pode fazer múltiplas (2+) por hierarquia se tiver controle sobre todas as classes incluídas no processo - Isso significa que você não pode aplicar esta solução, por exemplo, com classes internas ou com classes que simplesmente não pode editar - se quiser fazer isso, fica com a solução @Franck - instâncias infantis.

... e finalmente exemplo com alguma saída:

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();

Quais saídas

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

Use características como classes base. Em seguida, use -os na classe pai. Estenda -o.

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();

Veja agora Business Woman Herited Business e Human, ambos;

<?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;
?>

Eu li vários artigos desencorajando a herança em projetos (em oposição às bibliotecas/estruturas) e encorajando a programar interfaces de agaisnt, sem implementações.
Eles também defendem OO por composição: se você precisar das funções nas classes A e B, faça C ter membros/campos desse tipo:

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();
    }
}

A herança múltipla parece funcionar no nível da interface. Fiz um teste no PHP 5.6.1.

Aqui está um código de trabalho:

<?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

Não achei que isso fosse possível, mas tropecei no código -fonte Swiftmailer, na classe swift_transport_iobuffer, que tem a seguinte definição:

interface Swift_Transport_IoBuffer extends Swift_InputByteStream, Swift_OutputByteStream

Ainda não brinquei com isso, mas achei que seria interessante compartilhar.

Acabei de resolver meu problema de "herança múltipla" com:

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;
    }

}

Dessa forma, tenho o poder de manipular a sessão dentro de uma resposta de sessão que estende o MyServicerSponseType que ainda pode lidar com a sessão por si só.

Você pode fazer isso usando características em PHP, anunciado a partir de Php 5.4

Aqui está um tutorial rápido para você, http://culttt.com/2014/06/25/php-traits/

O PHP ainda não suporta a herança de várias classes, mas suporta a herança de múltiplas interface.

Ver http://www.hudzilla.org/php/6_17_0.php Para alguns exemplos.

O PHP não permite herança múltipla, mas você pode fazer com a implementação de várias interfaces. Se a implementação for "pesada", forneça implementação esquelética Para cada interface em uma classe separada. Então você pode Delegar toda a classe de interface para essas implementações esqueléticas através da contenção de objetos.

Sem saber exatamente o que você está tentando alcançar, sugiro procurar a possibilidade de redesenhar o aplicativo para usar a composição em vez de herança neste caso.

Sempre boa idéia é fazer da classe pai, com funções ... ou seja, adicione essa funcionalidade ao pai.

E "mover" todas as classes que usam isso hierarquicamente para baixo. Eu preciso de funções de reescrita, que são específicas.

Se você deseja verificar se uma função é pública, consulte este tópico: https://stackoverflow.com/a/4160928/2226755

E use o método Call_User_Func_ARRAY (...) para muitos ou não argumentos.

Assim :

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");

Um dos problemas do PHP como linguagem de programação é o fato de que você só pode ter herança única. Isso significa que uma classe só pode herdar de outra classe.

No entanto, na maioria das vezes seria benéfico herdar de várias classes. Por exemplo, pode ser desejável herdar métodos de algumas classes diferentes para evitar a duplicação de código.

Esse problema pode levar à classe que tem um longo histórico familiar de herança, que geralmente não faz sentido.

No Php 5.4, um novo recurso do idioma foi adicionado como características. Uma característica é como um mixin, pois permite misturar aulas de características em uma classe existente. Isso significa que você pode reduzir a duplicação de código e obter os benefícios, evitando os problemas de herança múltipla.

Características

classe a estende B {}

A classe B estende C {}

Então A estendeu B e C

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top