我可以在PHP中使用多于一个类扩展一个类吗?

时间:2008-12-10 14:02:57

标签: php class oop extends

如果我有几个具有我需要的功能的类但想要为组织单独存储,我可以扩展一个类来同时拥有它们吗?

即。 class a extends b extends c

编辑:我知道如何一次扩展一个类,但我正在寻找一种方法来使用多个基类立即扩展一个类--AFAIK你不能在PHP中做到这一点但应该有办法绕过它不诉诸class c extends bclass b extends a

20 个答案:

答案 0 :(得分:152)

回答你的编辑:

如果你真的想伪造多重继承,你可以使用魔术函数__call()。

这很难看,虽然它可以从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");

打印“abcdef”

答案 1 :(得分:123)

您不能拥有扩展两个基类的类。你不可能。

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

但是,您可以拥有如下的层次结构......

Matron extends Nurse    
Consultant extends Doctor

Nurse extends HumanEntity
Doctor extends HumanEntity

HumanEntity extends DatabaseTable
DatabaseTable extends AbstractTable

等等。

答案 2 :(得分:50)

您可以使用特征,希望这些特性可以从PHP 5.4中获得。

Traits是一种在单继承语言(如PHP)中重用代码的机制。 Trait旨在通过使开发人员能够在生活在不同类层次结构中的多个独立类中自由地重用方法集来减少单继承的某些限制。 Traits和类组合的语义以某种方式定义,这降低了复杂性并避免了与多重继承和Mixins相关的典型问题。

他们因支持更好的构图和重用而具有潜力,因此可以将它们集成到新版本的语言中,如Perl 6,Squeak,Scala,Slate和Fortress。特征也被移植到Java和C#。

更多信息:https://wiki.php.net/rfc/traits

答案 3 :(得分:17)

类并不仅仅是方法的集合。一个类应该代表一个抽象概念,其中状态(字段)和行为(方法)都会改变状态。使用继承只是为了得到一些理想的行为听起来像糟糕的OO设计,以及许多语言不允许多重继承的原因:为了防止“意大利面继承”,即扩展3个类,因为每个类都有你需要的方法,并最终得到一个继承100个方法和20个字段的类,但只使用其中的5个。

答案 4 :(得分:14)

我相信很快就会有添加混音的计划。

但在此之前,请接受已接受的答案。您可以抽象出一点来构建“可扩展”类:

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

请注意,在此模型中,“OtherClass”会“了解”$ foo。 OtherClass需要有一个名为“setExtendee”的公共函数来建立这种关系。然后,如果它的方法是从$ foo调用的,它可以在内部访问$ foo。但是,它不会访问任何私有/受保护的方法/变量,如真正的扩展类。

答案 5 :(得分:8)

使用traits作为基类。然后在父类中使用它们。扩展它。

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

现在看到女商人逻辑上继承了商业和人类两者;

答案 6 :(得分:8)

<?php
// what if we want to extend more then 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;
?>

答案 7 :(得分:8)

@Franck当前接受的答案可行但实际上并不是多继承,而是在范围之外定义的类的子实例,也有__call()简写 - 考虑在任何地方只使用$this->childInstance->method(args)你需要&#34;扩展&#34;中的ExternalClass类方法类。

确切答案

不,你不能,不是真的,正如manual of extends keyword所说:

  

扩展类总是依赖于单个基类,即   不支持多重继承。

真实答案

然而,正如@adam建议的那样,这并不禁止您使用多个分层继承。

你可以扩展一个类,另一个类和另一个类,等等......

这个非常简单的例子就是:

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

重要提示

正如您可能已经注意到的那样,如果您可以控制流程中包含的所有类,则您只能按层次结构执行多个(2+)内部关系 - 这意味着您无法申请这个解决方案例如使用内置类或您无法编辑的类 - 如果您想这样做,您将留下@Franck解决方案 - 子实例。

...最后以一些输出为例:

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

哪个输出

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

答案 8 :(得分:6)

我读过几篇不鼓励项目继承的文章(而不是图书馆/框架),鼓励编写强大的界面,不反对实现。
他们还通过组合提倡OO:如果你需要a和b类中的函数,那么使c具有这种类型的成员/字段:

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

答案 9 :(得分:3)

多重继承似乎在接口级别起作用。 我在php 5.6.1上做了一个测试。

这是一个有效的代码:

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

我不认为这是可能的,但我在SwiftMailer源代码中偶然发现了Swift_Transport_IoBuffer类,它具有以下定义:

interface Swift_Transport_IoBuffer extends Swift_InputByteStream, Swift_OutputByteStream

我还没玩过它,但我认为分享可能会很有趣。

答案 10 :(得分:1)

我刚刚解决了我的“多重继承”问题:

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

}

这样我就能够在SessionResponse中操作会话,扩展MyServiceResponsetype仍然可以自己处理Session。

答案 11 :(得分:1)

您可以使用PHP中的Traits(从PHP 5.4开始宣布

)来实现这一点

以下是您的快速教程http://culttt.com/2014/06/25/php-traits/

答案 12 :(得分:0)

我不知道你想要实现的目标,我建议在这种情况下考虑重新设计应用程序以使用合成而不是继承。

答案 13 :(得分:0)

PHP尚不支持多类继承,但它支持多接口继承。

有关示例,请参阅http://www.hudzilla.org/php/6_17_0.php

答案 14 :(得分:0)

如果您想检查某个功能是否公开,请参阅此主题:https://stackoverflow.com/a/4160928/2226755

对许多或不参数使用call_user_func_array(...)方法。

像这样:

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

答案 15 :(得分:0)

PHP不允许多重继承,但您可以实现多个接口。如果实现“很重”,请为单独的类中的每个接口提供骨架实现。然后,您可以通过对象包含将所有接口类委托给这些骨架实现

答案 16 :(得分:0)

总是好主意是使用函数创建父类...即将所有功能添加到父级。

并“移动”所有使用此层次结构的类。我需要 - 重写函数,这是特定的。

答案 17 :(得分:0)

PHP作为编程语言的一个问题是,您只能拥有单一继承。这意味着一个类只能从另一个类继承。

但是,很多时候从多个类继承是有益的。例如,可能需要从几个不同的类继承方法,以防止代码重复。

这个问题可能会导致具有悠久的继承家族历史的类通常没有意义。

在PHP 5.4中添加了一种称为Traits的语言新功能。 Trait有点像Mixin,它允许您将Trait类混合到现有类中。这意味着您可以减少代码重复并获得好处,同时避免多重继承问题。

Traits

答案 18 :(得分:-1)

这不是一个真实的答案,我们有重复的课程

...但是可以用:)

class A {
    //do some things
}

class B {
    //do some things
}

copy_B类是复制所有B类

class copy_B extends A {

    //do some things (copy class B)
}

class A_B extends copy_B{}

现在

class C_A extends A{}
class C_B extends B{}
class C_A_b extends A_B{}  //extends A & B

答案 19 :(得分:-2)

A类扩展B {}

B类扩展C {}

然后A扩展了B和C

豫ICP备18024241号-1