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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/356128/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 22:29:07  来源:igfitidea点击:

Can I extend a class using more than 1 class in PHP?

phpclassoopextends

提问by atomicharri

If I have several classes with functions that I need but want to store separately for organisation, can I extend a class to have both?

如果我有几个具有我需要的功能的类,但想单独存储以供组织使用,我可以扩展一个类以同时拥有这两个功能吗?

i.e. class a extends b extends c

IE class a extends b extends c

edit: I know how to extend classes one at a time, but I'm looking for a method to instantly extend a class using multiple base classes - AFAIK you can't do this in PHP but there should be ways around it without resorting to class c extends b, class b extends a

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

回答by Franck

Answering your edit :

回答您的编辑:

If you really want to fake multiple inheritance, you can use the magic function __call().

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

This is ugly though it works from class A user's point of view :

尽管从 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");

Prints "abcdef"

打印“abcdef”

回答by adam

You cannot have a class that extends two base classes. You could not have.

你不能有一个扩展两个基类的类。你不能有。

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

You could however have a hierarchy as follows...

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

Matron extends Nurse    
Consultant extends Doctor

Nurse extends HumanEntity
Doctor extends HumanEntity

HumanEntity extends DatabaseTable
DatabaseTable extends AbstractTable

and so on.

等等。

回答by Nikola Petkanski

You could use traits, which, hopefully, will be available from PHP 5.4.

您可以使用特性,希望从 PHP 5.4 开始可以使用特性。

Traits is a mechanism for code reuse in single inheritance languages such as PHP. A Trait is intended to reduce some limitations of single inheritance by enabling a developer to reuse sets of methods freely in several independent classes living in different class hierarchies. The semantics of the combination of Traits and classes is defined in a way, which reduces complexity and avoids the typical problems associated with multiple inheritance and Mixins.

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

They are recognized for their potential in supporting better composition and reuse, hence their integration in newer versions of languages such as Perl 6, Squeak, Scala, Slate and Fortress. Traits have also been ported to Java and C#.

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

More information: https://wiki.php.net/rfc/traits

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

回答by Michael Borgwardt

Classes are not meant to be just collections of methods. A class is supposed to represent an abstract concept, with both state (fields) and behaviour (methods) which changes the state. Using inheritance just to get some desired behaviour sounds like bad OO design, and exactly the reason why many languages disallow multiple inheritance: in order to prevent "spaghetti inheritance", i.e. extending 3 classes because each has a method you need, and ending up with a class that inherits 100 method and 20 fields, yet only ever uses 5 of them.

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

回答by Sam

There are plans for adding mix-ins soon, I believe.

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

But until then, go with the accepted answer. You can abstract that out a bit to make an "extendable" class:

但在那之前,请使用已接受的答案。您可以将其抽象化以制作一个“可扩展”类:

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 that in this model "OtherClass" gets to 'know' about $foo. OtherClass needs to have a public function called "setExtendee" to set up this relationship. Then, if it's methods are invoked from $foo, it can access $foo internally. It will not, however, get access to any private/protected methods/variables like a real extended class would.

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

回答by Alice

Use traits as base classes. Then use them in a parent class. Extend it .

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

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

See now business woman logically inherited business and human both;

现在看商界女强人顺理成章地继承了商业和人类两者;

回答by Mehdi Homeily

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

回答by jave.web

Currently accepted answer by @Franck will work but it is not in fact multiple inheritance but a child instance of class defined out of scope, also there is the __call()shorthand - consider using just $this->childInstance->method(args)anywhere you need ExternalClass class method in "extended" class.

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

Exact answer

准确答案

No you can't, respectively, not really, as manual of extendskeywordsays:

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

An extended class is always dependent on a single base class, that is, multiple inheritance is not supported.

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

Real answer

真实答案

However as @adam suggested correctly this does NOT forbids you to use multiple hierarchal inheritance.

但是,正如@adam 正确建议的那样,这并不禁止您使用多层次继承。

You CAN extend one class, with another and another with another and so on...

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

So pretty simple example on this would be:

所以非常简单的例子是:

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

Important note

重要的提示

As you might have noticed, you can only do multiple(2+) intehritance by hierarchy if you have control over all classes included in the process- that means, you can't apply this solution e.g. with built-in classes or with classes you simply can't edit - if you want to do that, you are left with the @Franck solution - child instances.

正如您可能已经注意到的,如果您可以控制流程中包含的所有类则只能按层次结构执行多个 (2+) 集成- 这意味着,您不能将此解决方案应用于例如内置类或您的类根本无法编辑 - 如果你想这样做,你会留下@Franck 解决方案 - 子实例。

...And finally example with some output:

...最后的一些输出示例:

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

Which outputs

哪些输出

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

回答by PhiLho

I have read several articles discouraging inheritance in projects (as opposed to libraries/frameworks), and encouraging to program agaisnt interfaces, no against implementations.
They also advocate OO by composition: if you need the functions in class a and b, make c having members/fields of this type:

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

回答by ling

Multiple inheritance seems to work at the interface level. I made a test on php 5.6.1.

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

Here is a working code:

这是一个工作代码:

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

I didn't think that was possible, but I stumbled upon in the SwiftMailer source code, in the Swift_Transport_IoBuffer class, which has the following definition:

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

interface Swift_Transport_IoBuffer extends Swift_InputByteStream, Swift_OutputByteStream

I didn't play with it yet, but I thought it might be interesting to share.

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