将stdClass对象转换/转换为另一个类

The*_*uck 86 php stdclass

我正在使用第三方存储系统,它只返回我的stdClass对象,无论我输入什么因为一些不明原因.所以我很想知道是否有办法将stdClass对象转换/转换为给定类型的完整对象.

例如,有些东西:

//$stdClass is an stdClass instance
$converted = (BusinessClass) $stdClass;
Run Code Online (Sandbox Code Playgroud)

我只是将stdClass转换为数组并将其提供给BusinessClass构造函数,但也许有一种方法可以恢复我不知道的初始类.

注意:我对"更改您的存储系统"类型的答案不感兴趣,因为它不是您感兴趣的点.请将其视为关于语言能力的学术问题.

干杯

Gor*_*don 87

有关可能的演员表,请参阅Type Juggling手册.

允许的演员阵容是:

  • (int),(integer) - 强制转换为整数
  • (bool),(boolean) - 强制转换为布尔值
  • (浮动),(双),(真实) - 施放到浮动
  • (字符串) - 强制转换为字符串
  • (数组) - 强制转换为数组
  • (对象) - 强制转换为对象
  • (未设置) - 强制转换为NULL(PHP 5)

你必须编写一个Mapper来执行从stdClass到另一个具体类的转换.不应该太难做.

或者,如果您处于一种骇人的心情,您可以调整以下代码:

function arrayToObject(array $array, $className) {
    return unserialize(sprintf(
        'O:%d:"%s"%s',
        strlen($className),
        $className,
        strstr(serialize($array), ':')
    ));
}
Run Code Online (Sandbox Code Playgroud)

伪造一个数组到某个类的对象.这通过首先序列化数组然后更改序列化数据以使其代表某个类来工作.然后,结果将反序列化为此类的实例.但就像我说的那样,它是黑客,所以期待副作用.

对于对象,代码将是

function objectToObject($instance, $className) {
    return unserialize(sprintf(
        'O:%d:"%s"%s',
        strlen($className),
        $className,
        strstr(strstr(serialize($instance), '"'), ':')
    ));
}
Run Code Online (Sandbox Code Playgroud)

  • 这种黑客是一种聪明的技巧.不会使用它,因为我目前解决问题的方法更稳定,但仍然很有趣. (9认同)

小智 51

你可以使用上面的函数来编译不相似的类对象(PHP> = 5.3)

/**
 * 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;
}
Run Code Online (Sandbox Code Playgroud)

例:

class A 
{
  private $_x;   
}

class B 
{
  public $_x;   
}

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

$x = cast('A',$b);
$x = cast('B',$a);
Run Code Online (Sandbox Code Playgroud)

  • 我必须说,这是一个非常优雅的解决方案!我只是想知道它的规模如何......反思让我害怕. (5认同)
  • 很好的解决方案,如果您需要避免调用构造函数。 (3认同)
  • 正如 @Scuzzy 指出的,您可能希望避免调用构造函数,因为它可能会引发异常或导致错误。毕竟我认为这个答案被低估了。 (2认同)

hak*_*kre 14

要将a的所有现有属性移动stdClass到指定类名的新对象:

/**
 * recast stdClass object to an object with type
 *
 * @param string $className
 * @param stdClass $object
 * @throws InvalidArgumentException
 * @return mixed new, typed object
 */
function recast($className, stdClass &$object)
{
    if (!class_exists($className))
        throw new InvalidArgumentException(sprintf('Inexistant class %s.', $className));

    $new = new $className();

    foreach($object as $property => &$value)
    {
        $new->$property = &$value;
        unset($object->$property);
    }
    unset($value);
    $object = (unset) $object;
    return $new;
}
Run Code Online (Sandbox Code Playgroud)

用法:

$array = array('h','n');

$obj=new stdClass;
$obj->action='auth';
$obj->params= &$array;
$obj->authKey=md5('i');

class RestQuery{
    public $action;
    public $params=array();
    public $authKey='';
}

$restQuery = recast('RestQuery', $obj);

var_dump($restQuery, $obj);
Run Code Online (Sandbox Code Playgroud)

输出:

object(RestQuery)#2 (3) {
  ["action"]=>
  string(4) "auth"
  ["params"]=>
  &array(2) {
    [0]=>
    string(1) "h"
    [1]=>
    string(1) "n"
  }
  ["authKey"]=>
  string(32) "865c0c0b4ab0e063e5caa3387c1a8741"
}
NULL
Run Code Online (Sandbox Code Playgroud)

这是有限的,因为new操作员不知道它需要哪些参数.对于你的情况可能适合.


Ser*_*i G 10

我有一个非常类似的问题.简化的反射解决方案对我来说很好用:

public static function cast($destination, \stdClass $source)
{
    $sourceReflection = new \ReflectionObject($source);
    $sourceProperties = $sourceReflection->getProperties();
    foreach ($sourceProperties as $sourceProperty) {
        $name = $sourceProperty->getName();
        $destination->{$name} = $source->$name;
    }
    return $destination;
}
Run Code Online (Sandbox Code Playgroud)


Wiz*_*ard 8

希望有人觉得这很有用

// 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);
Run Code Online (Sandbox Code Playgroud)
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;
            }
        }
    }
} 
Run Code Online (Sandbox Code Playgroud)
class ModelFoo extends Castable
{
    public $id;
    public $value;
}
Run Code Online (Sandbox Code Playgroud)


小智 5

更改深度转换功能(使用递归)

/**
 * 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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)