我打算在该父项的构造函数中创建对象父项的克隆。简而言之:
class ParentClass {
protected $property;
public function __construct() {
$this->property = clone $this;
}
}
class ChildClass extends ParentClass {
}
这一切都很好,但是这个代码的问题是如果实例化ChildClass,则会使用ChildClass的实例填充受保护的属性。但是,无论类$this
引用什么,我都希望它是ParentClass的一个实例。
我当然可以组合debug_backtrace
和new self()
(为了避免无休止的构造函数调用递归)并将结果的ParentClass实例分配给属性,尽管这样的解决方案很详细,因为调试回溯只返回调用者类和方法的字符串名称。
最后,我可以将new self()
和参数的提供结合到对象的实例化中,指示是否应该创建“new self”,但我不喜欢解决方案,因为它的丑陋和冗余。
PHP中有没有办法找到“自我克隆”?
答案 0 :(得分:1)
正如评论中所讨论的,我认为这种模式不适合你的原因是你的对象层次结构设计不合理。在示例中,ChildClass
是“类型”ParentClass
,但也在内部引用ParentClass
的副本来执行某些委派工作。
从评论中,你所拥有的东西必须是这样的:
class BasicLogger {
protected $delegated_logger;
public function __construct() {
// initialise $this->delegated_logger somehow
}
public function logMessage($message, $flags) {
{
$prepared_message = $this->prepareMessage($message, $flags);
$this->deliverMessage($prepared_message);
}
private function prepareMessage($message, $flags) {
// implementation here
}
protected function deliverMessage($prepared_message) {
// implementation here
}
}
class MailLogger extends BasicLogger {
protected function deliverMessage($prepared_message) {
// different implementation here
if ( $mail_sending_failed ) {
$this->delegated_logger->logMessage('Oops, MailLogger failed...');
}
}
}
但是,BasicLogger
实际上在对象层次结构中执行多个角色:
logMessage
方法)prepareMessage
的共享实现,以及依赖于logMessage
和deliverMessage
函数的deliverMessage
的实现interface
的特定实现前三个角色应分为abstract
,interface Logger {
public function logMessage($message, $flags = null);
}
abstract class BaseLogger implements Logger {
public function logMessage($message, $flags = null) {
{
$prepared_message = $this->prepareMessage($message, $flags);
$this->deliverMessage($prepared_message);
}
private function prepareMessage($message, $flags) {
// implementation here
}
abstract protected function deliverMessage($prepared_message);
}
class BasicTextLogger extends BaseLogger {
protected function deliverMessage($prepared_message) {
// implementation here
}
}
基类和简单实现:
BasicTextLogger
然后,您可以在任何需要的位置使用BaseLogger
的实例,包括BasicLogger
的其他实现。
您可能希望将具有委派记录器(上面的BasicTextLogger
的第4个角色)的逻辑放入另一个类中以供重用。 abstract class ComplexLogger extends BaseLogger {
protected $delegated_logger;
public function __construct( Logger $delegated_logger ) {
if ( $delegated_logger instanceOf ComplexLogger ) {
throw new Exception('Attempted to delegate one complex logger to another; danger of recursion, so disallowed.');
} else {
$this->delegated_logger = $delegated_logger;
}
}
}
class MailLogger extends ComplexLogger {
protected function deliverMessage($prepared_message) {
// different implementation here
if ( $mail_sending_failed ) {
$this->delegated_logger->logMessage('Oops, MailLogger failed...');
}
}
}
不应该继承此行为,或者您最终需要向记录器提供记录器到记录器, ad infinitum 。
$my_logger = new MailLogger( new BasicTextLogger() );
$my_logger->logMessage('Hello World!');
然后,您可以执行依赖注入,为复杂的记录器提供一个简单的记录器来委派给:
class
这似乎有很多不同的interface
es和$delegated_logger
,但现在每个人都有明确的责任。您可以将整个MailLogger
逻辑放入Logger
,但如果您以后有另一个复杂的记录器,则必须复制并粘贴它。您也可以忽略BaseLogger
接口,只需输入从prepareMessage
类派生的类的提示,但是您可能希望实现不使用DoNothingLogger
完全 - 例如,{{1}}。