即
class a extends b extends c
编辑:我知道如何逐个扩展类,但我正在寻找一种通过多个基类即时扩展类的方法-据我所知,在PHP中无法实现这一点,但应该有不需要诉诸class c extends b
,class b extends a
的方法来解决。class a extends b extends c
编辑:我知道如何逐个扩展类,但我正在寻找一种通过多个基类即时扩展类的方法-据我所知,在PHP中无法实现这一点,但应该有不需要诉诸class c extends b
,class b extends a
的方法来解决。如果你真的想在 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"
一个类不能同时继承两个基类。以下代码是不合法的:
// 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
等等。
你可以使用Traits,希望这个特性能够在PHP 5.4及以上版本中使用。
Traits是一种代码重用机制,适用于单一继承的语言,例如PHP。Trait旨在通过使开发人员能够在不同类层次结构中的多个独立类中自由重用方法集来减少单一继承的某些限制。Traits和类的组合语义被定义为一种方式,以降低复杂性并避免与多重继承和Mixins相关的典型问题。
它们因其在支持更好的组成和重用方面的潜力而得到认可,因此它们被集成到Perl 6、Squeak、Scala、Slate和Fortress等新版本语言中。Traits也被移植到Java和C#中。
从PHP 5.4.0开始,有“Traits”——您可以在一个类中使用多个trait,因此最终决定点将是您是否需要真正的继承或者只需要一些“特性”(trait)。Trait模糊地说是一个已经实现的接口,它只是用于use
。
不,您不能,或者说不完全可以,因为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
类不应只是一些方法的集合。类应该代表一个抽象概念,既有状态(字段),也有行为(方法),从而改变状态。仅仅使用继承来获得某些期望的行为听起来像是糟糕的面向对象设计,这也是为什么许多语言禁止多重继承的原因:为了防止“意大利面式继承”,例如,扩展3个类,因为每个类都有你需要的方法,结果得到一个继承100个方法和20个字段的类,但只使用其中的5个。
将 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();
现在看,商务女性在理性上继承了商业和人类两者;
据我所知,很快就会有添加混合项的计划。
但在那之前,请按照被接受的答案来进行。您可以将其抽象出一点,以创建一个“可扩展”的类:
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。但是,它将不会像真正的扩展类一样获得对任何私有/受保护方法/变量的访问权限。
<?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;
?>
我读过几篇文章,反对在项目中使用继承(相对于库/框架),并鼓励针对接口编程而不是实现。
他们还提倡通过组合实现面向对象编程:如果需要类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();
}
}
多重继承在接口层面上似乎是可行的。
我在 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
我还没有玩过它,但是我想分享一下��能会很有趣。