Convert/cast an stdClass object to another class

2020-01-23 10:45发布

I'm using a third party storage system that only returns me stdClass objects no matter what I feed in for some obscure reason. So I'm curious to know if there is a way to cast/convert an stdClass object into a full fledged object of a given type.

For instance something along the lines of:

//$stdClass is an stdClass instance
$converted = (BusinessClass) $stdClass;

I am just casting the stdClass into an array and feed it to the BusinessClass constructor, but maybe there is a way to restore the initial class that I am not aware of.

Note: I am not interested in 'Change your storage system' type of answers since it is not the point of interest. Please consider it more an academic question on the language capacities.

Cheers

标签: php stdclass
10条回答
家丑人穷心不美
2楼-- · 2020-01-23 11:11

Changed function for deep casting (using recursion)

/**
 * Translates type
 * @param $destination Object destination
 * @param stdClass $source Source
 */
private static function Cast(&$destination, stdClass $source)
{
    $sourceReflection = new \ReflectionObject($source);
    $sourceProperties = $sourceReflection->getProperties();
    foreach ($sourceProperties as $sourceProperty) {
        $name = $sourceProperty->getName();
        if (gettype($destination->{$name}) == "object") {
            self::Cast($destination->{$name}, $source->$name);
        } else {
            $destination->{$name} = $source->$name;
        }
    }
}
查看更多
神经病院院长
3楼-- · 2020-01-23 11:14

Hope that somebody find this useful

// new instance of stdClass Object
$item = (object) array(
    'id'     => 1,
    'value'  => 'test object',
);

// cast the stdClass Object to another type by passing
// the value through constructor
$casted = new ModelFoo($item);

// OR..

// cast the stdObject using the method
$casted = new ModelFoo;
$casted->cast($item);
class Castable
{
    public function __construct($object = null)
    {
        $this->cast($object);
    }

    public function cast($object)
    {
        if (is_array($object) || is_object($object)) {
            foreach ($object as $key => $value) {
                $this->$key = $value;
            }
        }
    }
} 
class ModelFoo extends Castable
{
    public $id;
    public $value;
}
查看更多
smile是对你的礼貌
4楼-- · 2020-01-23 11:15

consider adding a new method to BusinessClass:

public static function fromStdClass(\stdClass $in): BusinessClass
{
  $out                   = new self();
  $reflection_object     = new \ReflectionObject($in);
  $reflection_properties = $reflection_object->getProperties();
  foreach ($reflection_properties as $reflection_property)
  {
    $name = $reflection_property->getName();
    if (property_exists('BusinessClass', $name))
    {
      $out->{$name} = $in->$name;
    }
  }
  return $out;
}

then you can make a new BusinessClass from $stdClass:

$converted = BusinessClass::fromStdClass($stdClass);
查看更多
劫难
5楼-- · 2020-01-23 11:16

BTW: Converting is highly important if you are serialized, mainly because the de-serialization breaks the type of objects and turns into stdclass, including DateTime objects.

I updated the example of @Jadrovski, now it allows objects and arrays.

example

$stdobj=new StdClass();
$stdobj->field=20;
$obj=new SomeClass();
fixCast($obj,$stdobj);

example array

$stdobjArr=array(new StdClass(),new StdClass());
$obj=array(); 
$obj[0]=new SomeClass(); // at least the first object should indicates the right class.
fixCast($obj,$stdobj);

code: (its recursive). However, i don't know if its recursive with arrays. May be its missing an extra is_array

public static function fixCast(&$destination,$source)
{
    if (is_array($source)) {
        $getClass=get_class($destination[0]);
        $array=array();
        foreach($source as $sourceItem) {
            $obj = new $getClass();
            fixCast($obj,$sourceItem);
            $array[]=$obj;
        }
        $destination=$array;
    } else {
        $sourceReflection = new \ReflectionObject($source);
        $sourceProperties = $sourceReflection->getProperties();
        foreach ($sourceProperties as $sourceProperty) {
            $name = $sourceProperty->getName();
            if (is_object(@$destination->{$name})) {
                fixCast($destination->{$name}, $source->$name);
            } else {
                $destination->{$name} = $source->$name;
            }
        }
    }
}
查看更多
登录 后发表回答