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

I intend to create a clone of an object's parent within the constructor of that parent. In short:

class ParentClass {
    protected $property;

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

class ChildClass extends ParentClass {

}

This works all fine, yet the problem with this code is the protected property getting populated with an instance of the ChildClass, in case the ChildClass is instantiated. I would however like it to be an instance of the ParentClass regardless of the class $this refers to.

I could of course combine debug_backtrace and new self() (in order to avoid endless recursion of constructor invocations) and assign the resulting ParentClass instance to the property, though such a soluation is verbose, as debug backtrace only returns string names of caller classes and methods.

Lastly, I could combine new self() and the provision of an argument to the instantiation of the object indicating if a "new self" should be created, but I dislike the solution because of its ugliness and redundancy.

Is there a way in PHP to find a "clone of self"?

As discussed in the comments, I think the reason this pattern is not working for you is that you have a poorly designed object hierarchy. In the example, ChildClass is a "type of" ParentClass, but also internally references a copy of ParentClass to do some delegated work.

From the comments, what you have must look something like this:

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...');
         }
    }
}

However, BasicLogger is actually performing multiple roles in the object hierarchy:

  1. defining the interface that all loggers should adhere to (here represented as a single logMessage method)
  2. providing a shared implementation of prepareMessage that all loggers will use, and an implementation of logMessage that depends on it plus a deliverMessage function
  3. providing a specific implementation of deliverMessage that will be completely over-written by child classes
  4. providing a mechanism for complex implementations to delegate to simpler implementations, without a way of distinguishing between the two

The first three roles should be separated into an interface, an abstract base class, and a simple implementation:

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
    }
}

You can then use instances of BasicTextLogger wherever you need, including in other implementations of BaseLogger.

You might want to put the logic of having a delegated logger (the 4th role of my BasicLogger above) into another class for reuse. BasicTextLogger shouldn't inherit this behaviour, or you'll end up needing to provide a logger to a logger to a logger to a logger, ad infinitum.

 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...');
         }
     }
 }

This then allows you to perform Dependency Injection to provide your complex logger with a simple logger to delegate to:

 $my_logger = new MailLogger( new BasicTextLogger() );
 $my_logger->logMessage('Hello World!');

This may seem like a lot of different classes and interfaces, but each now has a clear responsibility. You could put the whole $delegated_logger logic into MailLogger, but you'd have to copy and paste it if you had another complex logger later. You might also be able to ignore the Logger interface, and just type-hint for classes deriving from the BaseLogger class, but it's possible you'll want an implementation that doesn't use prepareMessage at all - for instance, a DoNothingLogger.