Is it possible to instantiate as child object but

2019-09-05 22:35发布

问题:

I'm running into a problem working around limitations in Zend Framework 1.x and I can't replace or update it at the moment. I have a novel idea but I'm not sure if it's possible.

The basic question is Is it possible to instantiate an extending child object, but then extract the parent object afterward for serialization?

To illustrate why, essentially the Zend_Mail class has some really stupid limitations and type checks on its methods, in my case specifically $mail->setType().

My thought is that I can create an extending class (My_Zend_Mail extends Zend_Mail), then override the setType() {...} method in my class, eliminating the restrictions, allowing me to set certain protected properties in the Zend_Mail class. The limitation is that I need to hand this off to a remote server as a serialized object, and that remote server will NOT have or recognize the My_Zend_Mail class when it's unserialized. So I need to serialize only the Zend_Mail parent at my end.

So back to the original question, can I extract a parent object, after it's been instantiated via an extending child?


EDIT: I've found the following question whose selected answer proposes a hackish way to recast a serialized string so that it unserializes as a different object....

Convert/cast an stdClass object to another class

This might work, though further down it looks like someone is doing this via the Reflection class as well, which is closer to what I'm looking for. I might give that a shot and report back, unless there are other suggestions?

回答1:

I was able to find another answer by using slightly different search criteria dealing more with casting than extracting. The solution that ended up working for me was based on the reflection classes which I admitedly have only a little experience with, the original answer is found here:

https://stackoverflow.com/a/9812059/1058733

I'm duplicating the code for posterity here, but this was directly copied...

/**
 * Class casting
 *
 * @param string|object $destination
 * @param object $sourceObject
 * @return object
 */
function cast($destination, $sourceObject)
{
    if (is_string($destination)) {
        $destination = new $destination();
    }
    $sourceReflection = new ReflectionObject($sourceObject);
    $destinationReflection = new ReflectionObject($destination);
    $sourceProperties = $sourceReflection->getProperties();
    foreach ($sourceProperties as $sourceProperty) {
        $sourceProperty->setAccessible(true);
        $name = $sourceProperty->getName();
        $value = $sourceProperty->getValue($sourceObject);
        if ($destinationReflection->hasProperty($name)) {
            $propDest = $destinationReflection->getProperty($name);
            $propDest->setAccessible(true);
            $propDest->setValue($destination,$value);
        } else {
            $destination->$name = $value;
        }
    }
    return $destination;
}

And the example usage was illustrated like so...

class A {
  private $_x;   
}

class B {
  public $_x;   
}

$a = new A();
$b = new B();

$x = cast('A',$b);
$x = cast('B',$a);

So in the end the reflection class is giving us the ability to access the protected parameters within Zend_Mail without having to extend it. I could have rewritten the method to skip the step where we DO extend the original class to set the values, and then use this method to cast it, but leaving it like this is more OO and allows me to use this convenient trick elsewhere.

Hope that helps!