如果我有几个类,我需要的功能,但想要为组织单独存储,我可以扩展一个类同时拥有它们吗?
即 class a extends b extends c
编辑:我知道如何一次扩展一个类,但我正在寻找一种方法来使用多个基类立即扩展一个类--AFAIK你不能在PHP中做到这一点但是应该有办法解决它而不诉诸于class c extends b
,class b extends a
回答你的编辑:
如果你真的想伪造多重继承,你可以使用魔术函数__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
等等.
您可以使用特征,希望可以从PHP 5.4获得.
Traits是一种在单继承语言(如PHP)中重用代码的机制.Trait旨在通过使开发人员能够在生活在不同类层次结构中的多个独立类中自由地重用方法集来减少单继承的某些限制.Traits和类组合的语义以某种方式定义,这降低了复杂性并避免了与多重继承和Mixins相关的典型问题.
他们因支持更好的组合和重用而具有潜力,因此可以将它们集成到新版本的语言中,如Perl 6,Squeak,Scala,Slate和Fortress.特征也被移植到Java和C#.
更多信息:https://wiki.php.net/rfc/traits
类并不仅仅是方法的集合.一个类应该代表一个抽象概念,其中状态(字段)和行为(方法)都会改变状态.使用继承只是为了得到一些理想的行为听起来像糟糕的OO设计,以及许多语言不允许多重继承的原因:为了防止"意大利面继承",即扩展3个类,因为每个类都有你需要的方法,并最终得到一个继承100方法和20个字段的类,但只使用其中的5个.
我相信很快就会计划加入混合体.
但在那之前,请接受已接受的答案.您可以抽象出一点来构建一个"可扩展"类:
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.但是,它不会像真正的扩展类那样访问任何私有/受保护的方法/变量.
_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; ?>
使用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();
现在看到商界女性逻辑上继承了商业和人类两者;
@Franck目前接受的答案是可行的,但它实际上并不是多继承,而是在范围之外定义的类的子实例,也有__call()
简写 - 考虑$this->childInstance->method(args)
在"扩展"类中使用 任何需要ExternalClass类方法的地方.
不,你不能分别,不是真的,因为关键字手册extends
说:
扩展类始终依赖于单个基类,即不支持多重继承.
但是,正如@adam建议的那样,这并不禁止您使用多个分层继承.
你可以扩展一个类,另一个类和另一个类,等等......
这个非常简单的例子就是:
class firstInheritance{} class secondInheritance extends firstInheritance{} class someFinalClass extends secondInheritance{} //...and so on...
您可能已经注意到,如果您可以控制流程中包含的所有类,那么您只能按层次结构执行多个(2+)intehritance - 这意味着,您无法应用此解决方案,例如内置类或类根本无法编辑 - 如果你想这样做,你将留下@Franck解决方案 - 子实例.
...最后以一些输出为例:
class A{ function a_hi(){ echo "I am a of A".PHP_EOL."
".PHP_EOL; } } class B extends A{ function b_hi(){ echo "I am b of B".PHP_EOL."
".PHP_EOL; } } class C extends B{ function c_hi(){ echo "I am c of C".PHP_EOL."
".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
我已经阅读了几篇文章,这些文章阻止了项目中的继承(而不是库/框架),并鼓励编写agaisnt接口,而不是实现.
他们还通过组合提倡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(); } }