I have a class where it may be necessary to change the object to a descendent class further down the line. Is this possible? I know that one option is to return a copy of it
For simple classes this may work (I am using this successfully in some rare cases):
function castAs($sourceObject, $newClass)
{
    $castedObject                    = new $newClass();
    $reflectedSourceObject           = new \ReflectionClass($sourceObject);
    $reflectedSourceObjectProperties = $reflectedSourceObject->getProperties();
    foreach ($reflectedSourceObjectProperties as $reflectedSourceObjectProperty) {
        $propertyName = $reflectedSourceObjectProperty->getName();
        $reflectedSourceObjectProperty->setAccessible(true);
        $castedObject->$propertyName = $reflectedSourceObjectProperty->getValue($sourceObject);
    }
}
Usage in my case:
$indentFormMapper = castAs($formMapper, IndentedFormMapper::class);
More abstract:
$castedObject = castAs($sourceObject, TargetClass::class);
Of course TargetClass has to inherit from the class of sourceObject and you have to make all protected and private properties public in TargetClass to get this work.
I use this to change FormMapper (https://github.com/sonata-project/SonataAdminBundle/blob/3.x/src/Form/FormMapper.php) on the fly to IndentedFormMapper by adding a new method called chain:
class IndentedFormMapper extends FormMapper
{
    /**
     * @var AdminInterface
     */
    public $admin;
    /**
     * @var BuilderInterface
     */
    public $builder;
    /**
     * @var FormBuilderInterface
     */
    public $formBuilder;
    /**
     * @var string|null
     */
    public $currentGroup;
    /**
     * @var string|null
     */
    public $currentTab;
    /**
     * @var bool|null
     */
    public $apply;
    public function __construct()
    {
    }
    /**
     * @param $callback
     * @return $this
     */
    public function chain($callback)
    {
        $callback($this);
        return $this;
    }
}