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

如果我有几个函数类,我需要,但要单独存储的组织,我可以扩展一个类有两个?

class a extends b extends c

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

307492 次浏览

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

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

不能有一个扩展了两个基类的类:

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

诸如此类。

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

如果你真的想在 PHP 5.3中伪造多重继承,你可以使用魔法函数 _ _ 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”

PHP 不支持多重继承,但是你可以实现多个接口。如果实现是“重”的,那么在一个单独的类中为每个接口提供 骨架实施。然后,你可以通过 对象包容 将所有接口类委托给这些骨架实现

我读过几篇不鼓励在项目中继承(相对于库/框架)的文章,并鼓励针对接口编程,而不是针对实现。
它们还通过组合提倡面向对象: 如果需要类 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();
}
}

我相信很快就会有增加混搭的计划。

但是在那之前,还是接受这个答案吧。你可以把它抽象出来,创建一个“可扩展”的类:

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

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

总是好主意是使父类,与函数... 即添加这所有的功能到父类。

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

您可以使用 trait,但愿它可以从 PHP 5.4中获得。

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

它们在支持更好的组合和重用方面的潜力得到了认可,因此它们可以集成到更新版本的语言中,比如 Perl 6、 Squeak、 Scala、 Slate 和 Forfort。Traits 也被移植到 Java 和 C # 。

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

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

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 中操作 Session,它扩展了 MyServiceResponsetype,仍然可以自己处理 Session。

如果要检查函数是否为公共函数,请参阅以下主题: 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");
<?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;
?>

编辑: 2020 PHP 5.4 + 和7 +

在 PHP5.4.0中有“ 特质”——你可以在一个类中使用更多的 trait,所以最后的决定点是你想要 真的是遗产还是 只是需要 一些“特征”(性状)。模糊地说,Trait 是一个已经实现的接口,意味着只是 used。


目前被@Franck 接受的答案是可行的,但实际上它不是多重继承,而是一个在作用域之外定义的类的子实例,还有一个‘ _ _ call ()’的简写——考虑只使用‘ $this-> children Instance-> method (args)’在任何需要 ExternalClass 类方法的“扩展”类中。

正确答案

不,你不能,分别,不是真的,正如 extends关键字手册所说:

扩展类始终依赖于单个基类,即, 多重继承不受支持。

真正的答案

然而,正如@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

您可以使用 PHP 中的 Traits 来完成这项工作,它是从 PHP 5.4开始发布的

这里是一个快速教程为您,http://culttt.com/2014/06/25/php-traits/

多重继承似乎在接口层面起作用。 我在 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

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

interface Swift_Transport_IoBuffer extends Swift_InputByteStream, Swift_OutputByteStream

我还没玩过,但我觉得分享一下会很有趣。

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

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

这个问题可能导致类具有很长的家族继承史,这通常是没有意义的。

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

特质

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

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

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

类扩展 B {}

类扩展 C {}

然后 A 同时扩展了 B 和 C