将对象克隆保存为受保护属性

时间:2014-01-19 19:59:43

标签: php this clone self

我打算在该父项的构造函数中创建对象父项的克隆。简而言之:

class ParentClass {
    protected $property;

    public function __construct() {
        $this->property = clone $this;
    }
}

class ChildClass extends ParentClass {

}

这一切都很好,但是这个代码的问题是如果实例化ChildClass,则会使用ChildClass的实例填充受保护的属性。但是,无论类$this引用什么,我都希望它是ParentClass的一个实例。

我当然可以组合debug_backtracenew self()(为了避免无休止的构造函数调用递归)并将结果的ParentClass实例分配给属性,尽管这样的解决方案很详细,因为调试回溯只返回调用者类和方法的字符串名称。

最后,我可以将new self()和参数的提供结合到对象的实例化中,指示是否应该创建“new self”,但我不喜欢解决方案,因为它的丑陋和冗余。

PHP中有没有办法找到“自我克隆”?

1 个答案:

答案 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实际上在对象层次结构中执行多个角色:

  1. 定义所有记录器应遵守的接口(此处表示为单个logMessage方法)
  2. 提供所有记录器将使用的prepareMessage的共享实现,以及依赖于logMessagedeliverMessage函数的deliverMessage的实现
  3. 提供将由子类完全覆盖的interface的特定实现
  4. 为复杂的实现提供一种机制,以委托更简单的实现,而无需区分两者
  5. 前三个角色应分为abstractinterface 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}}。