如果我有几个具有所需功能的类,但想单独存储以便组织使用,我可以扩展一个类以同时拥有这两个类吗?
即 class a extends b extends c
编辑:我知道如何一次扩展一个类,但是我正在寻找一种使用多个基类立即扩展一个类的方法-AFAIK您无法在PHP中做到这一点,但是应该有一些解决方法,而不必诉诸于此class c extends b
,class b extends a
如果我有几个具有所需功能的类,但想单独存储以便组织使用,我可以扩展一个类以同时拥有这两个类吗?
即 class a extends b extends c
编辑:我知道如何一次扩展一个类,但是我正在寻找一种使用多个基类立即扩展一个类的方法-AFAIK您无法在PHP中做到这一点,但是应该有一些解决方法,而不必诉诸于此class c extends b
,class b extends a
Answers:
回答您的编辑:
如果您真的想伪造多重继承,则可以使用魔术函数__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中获得。
特性是一种在PHP等单一继承语言中重用代码的机制。特性旨在通过使开发人员在生活在不同类层次结构中的几个独立类中自由重用方法集,从而减少单一继承的某些限制。特性和类的组合的语义以某种方式定义,这降低了复杂性并避免了与多重继承和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。但是,它将无法像真正的扩展类那样访问任何私有/受保护的方法/变量。
使用特征作为基类。然后在父类中使用它们。扩展它。
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();
现在看女商人在逻辑上继承了商业和人类两者;
BusinessWoman
代替BusinessPerson
?然后,您可以进行实际的多重继承。
<?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;
?>
@Franck当前接受的答案将起作用,但是实际上它不是多重继承,而是超出范围定义的类的子实例,还有一种__call()
简写方式-考虑$this->childInstance->method(args)
在“扩展”类中仅使用 需要外部类方法的任何地方。
不,您不能,分别不是,正如关键字的手册所述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
我读过几篇文章,这些文章不鼓励在项目中进行继承(相对于库/框架),并鼓励对不可靠的接口进行编程,而不反对实现。
他们还通过构成提倡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();
}
}
多重继承似乎在接口级别上起作用。我在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
我还没有玩过,但是我认为分享可能会很有趣。
我刚刚使用以下方法解决了“多重继承”问题:
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。
如果要检查某个功能是否公开,请参见以下主题: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 5.4中宣布的特性来做到这一点
这是为您提供的快速教程,http://culttt.com/2014/06/25/php-traits/
PHP尚不支持多类继承,但是它支持多接口继承。
有关某些示例,请参见http://www.hudzilla.org/php/6_17_0.php。
总是好主意是使父类具有函数……即,将所有这些功能添加到父类。
并“向下移动”使用该层次结构的所有类。我需要-重写特定的功能。