PHP 中的多重继承
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/90982/
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
Multiple Inheritance in PHP
提问by Alex Weinstein
I'm looking for a good, clean way to go around the fact that PHP5 still doesn't support multiple inheritance. Here's the class hierarchy:
我正在寻找一种好的、干净的方法来解决 PHP5 仍然不支持多重继承的事实。这是类层次结构:
Message
-- TextMessage
-------- InvitationTextMessage
-- EmailMessage
-------- InvitationEmailMessage
Message
-- TextMessage
-------- InvitationTextMessage
-- EmailMessage
-------- InvitationEmailMessage
The two types of Invitation* classes have a lot in common; i'd love to have a common parent class, Invitation, that they both would inherit from. Unfortunately, they also have a lot in common with their current ancestors... TextMessage and EmailMessage. Classical desire for multiple inheritance here.
两种类型的邀请*类有很多共同点;我很想有一个共同的父类,邀请,他们都可以继承。不幸的是,他们与他们现在的祖先也有很多共同点……TextMessage 和 EmailMessage。这里是多重继承的经典愿望。
What's the most light-weight approach to solve the issue?
解决问题的最轻量级方法是什么?
Thanks!
谢谢!
回答by Micha? Rudnicki
Alex, most of the times you need multiple inheritance is a signal your object structure is somewhat incorrect. In situation you outlined I see you have class responsibility simply too broad. If Message is part of application business model, it should not take care about rendering output. Instead, you could split responsibility and use MessageDispatcher that sends the Message passed using text or html backend. I don't know your code, but let me simulate it this way:
亚历克斯,大多数时候你需要多重继承是你的对象结构有点不正确的信号。在你概述的情况下,我看到你的班级责任太广泛了。如果 Message 是应用程序业务模型的一部分,则它不应该关心渲染输出。相反,您可以拆分责任并使用 MessageDispatcher 发送使用文本或 html 后端传递的消息。我不知道你的代码,但让我以这种方式模拟它:
$m = new Message();
$m->type = 'text/html';
$m->from = 'John Doe <[email protected]>';
$m->to = 'Random Hacker <[email protected]>';
$m->subject = 'Invitation email';
$m->importBody('invitation.html');
$d = new MessageDispatcher();
$d->dispatch($m);
This way you can add some specialisation to Message class:
通过这种方式,您可以向 Message 类添加一些专业化:
$htmlIM = new InvitationHTMLMessage(); // html type, subject and body configuration in constructor
$textIM = new InvitationTextMessage(); // text type, subject and body configuration in constructor
$d = new MessageDispatcher();
$d->dispatch($htmlIM);
$d->dispatch($textIM);
Note that MessageDispatcher would make a decision whether to send as HTML or plain text depending on typeproperty in Message object passed.
请注意, MessageDispatcher 将根据type传递的 Message 对象中的属性决定是作为 HTML 还是纯文本发送。
// in MessageDispatcher class
public function dispatch(Message $m) {
if ($m->type == 'text/plain') {
$this->sendAsText($m);
} elseif ($m->type == 'text/html') {
$this->sendAsHTML($m);
} else {
throw new Exception("MIME type {$m->type} not supported");
}
}
To sum it up, responsibility is split between two classes. Message configuration is done in InvitationHTMLMessage/InvitationTextMessage class, and sending algorithm is delegated to dispatcher. This is called Strategy Pattern, you can read more on it here.
总而言之,责任分为两个类。消息配置在 InvitationHTMLMessage/InvitationTextMessage 类中完成,发送算法委托给调度员。这称为策略模式,您可以在此处阅读更多相关信息。
回答by Matthias Kestenholz
Maybe you can replace an 'is-a' relation with a 'has-a' relation? An Invitation might have a Message, but it does not necessarily need to 'is-a' message. An Invitation f.e. might be confirmed, which does not go well together with the Message model.
也许您可以用“has-a”关系替换“is-a”关系?邀请可能有一条消息,但它不一定需要“是”消息。可能会确认邀请 fe,这与 Message 模型不兼容。
Search for 'composition vs. inheritance' if you need to know more about that.
如果您需要了解更多信息,请搜索“组合与继承”。
回答by Simon East
If I can quote Phil in this thread...
如果我可以在这个线程中引用 Phil ...
PHP, like Java, does not support multiple inheritance.
Coming in PHP 5.4 will be traitswhich attempt to provide a solution to this problem.
In the meantime, you would be best to re-think your class design. You can implement multiple interfaces if you're after an extended API to your classes.
PHP 和 Java 一样,不支持多重继承。
PHP 5.4 中的特性将尝试为这个问题提供解决方案。
与此同时,你最好重新考虑你的班级设计。如果您追求类的扩展 API,则可以实现多个接口。
And Chris....
还有克里斯……
PHP doesn't really support multiple inheritance, but there are some (somewhat messy) ways to implement it. Check out this URL for some examples:
http://www.jasny.net/articles/how-i-php-multiple-inheritance/
PHP 并不真正支持多重继承,但有一些(有点混乱)的方法来实现它。查看此 URL 以获取一些示例:
http://www.jasny.net/articles/how-i-php-multiple-inheritance/
Thought they both had useful links. Can't wait to try out traits or maybe some mixins...
认为他们都有有用的链接。迫不及待地想尝试特征或一些混合...
回答by joelhardi
The Symfony framework has a mixin plugin for this, you might want to check it out -- even just for ideas, if not to use it.
Symfony 框架为此提供了一个mixin 插件,您可能想查看它——即使只是为了想法,如果不使用它。
The "design pattern" answer is to abstract the shared functionality into a separate component, and compose at runtime. Think about a way to abstract out the Invitation functionality out as a class that gets associated with your Message classes in some way other than inheritance.
“设计模式”的答案是将共享功能抽象到一个单独的组件中,并在运行时进行组合。考虑一种将 Invitation 功能抽象为一个类的方法,该类以继承以外的某种方式与您的 Message 类相关联。
回答by MatthewPearson
I'm using traits in PHP 5.4 as the way of solving this. http://php.net/manual/en/language.oop5.traits.php
我在 PHP 5.4 中使用特性作为解决这个问题的方法。 http://php.net/manual/en/language.oop5.traits.php
This allows for classic inheritance with extends, but also gives the possible of placing common functionality and properties into a 'trait'. As the manual says:
这允许使用扩展进行经典继承,但也提供了将常见功能和属性放入“特征”中的可能。正如手册所说:
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.
Traits 是一种在单继承语言(如 PHP)中代码重用的机制。Trait 旨在通过使开发人员能够在位于不同类层次结构中的多个独立类中自由重用方法集来减少单继承的一些限制。
回答by Ralph Ritoch
This is both a question and a solution....
这既是一个问题也是一个解决方案......
What about the magical _call(),_get(), __set() methods? I have not yet tested this solution but what if you make a multiInherit class. A protected variable in a child class could contain an array of classes to inherit. The constructor in the multi-interface class could create instances of each of the classes that are being inherited and link them to a private property, say _ext. The __call() method could use the method_exists() function on each of the classes in the _ext array to locate the correct method to call. __get() and __set could be used to locate internal properties, or if your an expert with references you could make the properties of the child class and the inherited classes be references to the same data. The multiple inheritance of your object would be transparent to code using those objects. Also, internal objects could access the inherited objects directly if needed as long as the _ext array is indexed by class name. I have envisioned creating this super-class and have not yet implemented it as I feel that if it works than it could lead to developing some vary bad programming habits.
那么神奇的 _ call() 呢,_get(), __set() 方法?我还没有测试过这个解决方案,但是如果你创建一个 multiInherit 类会怎样。子类中的受保护变量可以包含要继承的类数组。多接口类中的构造函数可以创建每个被继承的类的实例,并将它们链接到一个私有属性,比如 _ext。__call() 方法可以对 _ext 数组中的每个类使用 method_exists() 函数来定位要调用的正确方法。__get() 和 __set 可用于定位内部属性,或者如果您是具有引用的专家,您可以使子类和继承类的属性成为对相同数据的引用。对象的多重继承对于使用这些对象的代码是透明的。还,只要 _ext 数组按类名索引,内部对象就可以在需要时直接访问继承的对象。我已经设想创建这个超类,但尚未实现它,因为我觉得如果它有效,它可能会导致养成一些不同的不良编程习惯。
回答by danio
It sounds like the decorator patternmay be suitable, but hard to tell without more details.
听起来装饰者模式可能是合适的,但如果没有更多细节就很难说。
回答by danio
I have a couple of questions to ask to clarify what you are doing:
我有几个问题要问清楚你在做什么:
1) Does your message object justcontain a message e.g. body, recipient, schedule time? 2) What do you intend to do with your Invitation object? Does it need to be treated specially compared to an EmailMessage? 3) If so WHAT is so special about it? 4) If that is then the case, why do the message types need handling differently for an invitation? 5) What if you want to send a welcome message or an OK message? Are they new objects too?
1) 您的消息对象是否只包含一条消息,例如正文、收件人、计划时间?2)你打算用你的邀请对象做什么?与EmailMessage相比是否需要特殊对待?3) 如果是这样,它有什么特别之处?4) 如果是这样的话,为什么需要对邀请的消息类型进行不同的处理?5)如果你想发送欢迎信息或OK信息怎么办?它们也是新对象吗?
It does sound like you are trying combine too much functionality into a set of objects that should only be concerned with holding a message contents - and not how it should be handled. To me, you see, there is no difference between an invitation or a standard message. If the invitation requires special handling, then that means application logic and not a message type.
听起来您确实在尝试将太多功能组合到一组对象中,这些对象应该只关心保存消息内容 - 而不是应该如何处理它。对我来说,您看,邀请或标准消息之间没有区别。如果邀请需要特殊处理,那么这意味着应用程序逻辑而不是消息类型。
For example: a system I built had a shared base message object that was extended into SMS, Email, and other message types. However: these were not extended further - an invitation message was simply pre-defined text to be sent via a message of type Email. A specific Invitation application would be concerned with validation and other requirements for an invite. After all, all you want to do is send message X to recipient Y which should be a discrete system in its own right.
例如:我构建的系统有一个共享的基本消息对象,该对象扩展到 SMS、电子邮件和其他消息类型。但是:这些没有进一步扩展 - 邀请消息只是通过电子邮件类型的消息发送的预定义文本。特定的邀请应用程序将关注邀请的验证和其他要求。毕竟,您要做的就是将消息 X 发送给接收者 Y,而接收者 Y 本身应该是一个离散系统。
回答by Cheekysoft
PHP does support interfaces. This could be a good bet, depending on your use-cases.
PHP 确实支持接口。这可能是一个不错的选择,具体取决于您的用例。
回答by DeeCee
Same problem like Java. Try using interfaces with abstract functions for solving that problem
和Java一样的问题。尝试使用具有抽象函数的接口来解决该问题

