stdClass 객체를 다른 클래스로 변환 / 캐스트 있습니다. 그래서 stdClass 객체를 주어진

모호한 이유로 무엇을 공급하든 stdClass 객체 만 반환하는 타사 스토리지 시스템을 사용하고 있습니다. 그래서 stdClass 객체를 주어진 유형의 완전한 객체로 캐스트 / 변환하는 방법이 있는지 알고 싶습니다.

예를 들어 다음과 같은 내용이 있습니다.

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

stdClass를 배열로 캐스팅하고 BusinessClass 생성자에 공급하고 있지만 알지 못하는 초기 클래스를 복원하는 방법이있을 수 있습니다.

참고 : ‘스토리지 시스템 변경’유형의 답변은 관심 영역이 아니므로 관심이 없습니다. 언어 능력에 대한 학문적 질문이라고 생각하십시오.

건배



답변

가능한 캐스트 에 대해서는 Type Juggling 에 대한 설명서를 참조하십시오 .

허용되는 캐스트는 다음과 같습니다.

  • (int), (integer)-정수로 캐스트
  • (bool), (boolean)-부울로 캐스트
  • (float), (double), (real)-부동으로 캐스팅
  • (문자열)-문자열로 캐스트
  • (배열)-배열로 캐스트
  • (객체)-객체로 캐스트
  • (설정되지 않음)-NULL로 캐스트 (PHP 5)

stdClass에서 다른 구체적인 클래스로 캐스팅 하는 매퍼작성 해야합니다 . 너무 힘들어서는 안됩니다.

또는 당신이 끔찍한 분위기에 있다면 다음 코드를 수정할 수 있습니다.

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

특정 클래스의 객체로 배열을 의사 캐스팅합니다. 이것은 먼저 배열을 직렬화 한 다음 직렬화 된 데이터를 변경하여 특정 클래스를 나타내는 방식으로 작동합니다. 결과는이 클래스의 인스턴스로 직렬화 해제됩니다. 그러나 내가 말했듯이, 그것은 끔찍하므로 부작용을 기대하십시오.

객체 대 객체의 경우 코드는

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

답변

유사하지 않은 클래스 객체를 캐스팅하기 위해 위의 함수를 사용할 수 있습니다 (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;
}

예:

class A
{
  private $_x;
}

class B
{
  public $_x;
}

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

$x = cast('A',$b);
$x = cast('B',$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;
}

용법:

$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);

산출:

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

이것은 new어떤 매개 변수가 필요한지 알 수 없기 때문에 운영자 때문에 제한 됩니다. 귀하의 경우에 적합합니다.


답변

나는 매우 비슷한 문제가 있습니다. 단순화 된 반사 솔루션이 저에게 잘 맞았습니다.

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

답변

누군가가 유용하다고 생각하기를 바랍니다.

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

답변

딥 캐스팅 기능 변경 (재귀 사용)

/**
 * 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;
        }
    }
}

답변

데코레이터 패턴과 PHP 매직 게터 및 세터를 사용하는 또 다른 접근 방식 :

// A simple StdClass object    
$stdclass = new StdClass();
$stdclass->foo = 'bar';

// Decorator base class to inherit from
class Decorator {

    protected $object = NULL;

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

    public function __get($property_name)
    {
        return $this->object->$property_name;
    }

    public function __set($property_name, $value)
    {
        $this->object->$property_name = $value;
    }
}

class MyClass extends Decorator {}

$myclass = new MyClass($stdclass)

// Use the decorated object in any type-hinted function/method
function test(MyClass $object) {
    echo $object->foo . '<br>';
    $object->foo = 'baz';
    echo $object->foo;
}

test($myclass);