programing

stdClass 개체를 다른 클래스로 변환/캐스팅합니다.

goodjava 2022. 10. 22. 21:18

stdClass 개체를 다른 클래스로 변환/캐스팅합니다.

어떤 이유로 무엇을 입력하든 stdClass 객체만 반환하는 타사 스토리지 시스템을 사용하고 있습니다.따라서 stdClass 객체를 특정 유형의 완전한 개체로 캐스팅/변환할 수 있는 방법이 있는지 알고 싶습니다.

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

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

stdClass를 어레이에 삽입하여 BusinessClass 컨스트럭터에 공급하고 있습니다만, 제가 모르는 초기 클래스를 복원할 수 있는 방법이 있을지도 모릅니다.

참고: '스토리지 시스템 변경' 유형의 답변은 관심 사항이 아니므로 관심이 없습니다.언어 능력에 관한 학문적인 질문이라고 생각해 주세요.

건배.

가능한 캐스팅은 타입 저글링 매뉴얼을 참조하십시오.

허용되는 배역은 다음과 같습니다.

  • (int), (정수) - 정수로 주조
  • (부울), (부울) - 부울로 캐스팅
  • (2중), (2중), (실제) - 뜨기 위해 주조
  • (string) - 스트링에 캐스팅
  • (어레이) - 어레이에 캐스트
  • (객체) - 객체에 캐스팅
  • (설정 해제) - 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

입니다. , this, 음, 음, 음 this this this this this this this this this this this this this this.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;
        }
    }
}

비즈니스 클래스에 새로운 메서드를 추가하는 것을 검토합니다.

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

$stdClass에서 새로운 비즈니스 클래스를 만들 수 있습니다.

$converted = BusinessClass::fromStdClass($stdClass);

그리고 데코레이터 패턴과 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);

또 다른 접근법입니다.

최근 PHP 7 버전 덕분에 다음과 같은 작업이 가능합니다.

$theStdClass = (object) [
  'a' => 'Alpha',
  'b' => 'Bravo',
  'c' => 'Charlie',
  'd' => 'Delta',
];

$foo = new class($theStdClass)  {
  public function __construct($data) {
    if (!is_array($data)) {
      $data = (array) $data;
    }

    foreach ($data as $prop => $value) {
      $this->{$prop} = $value;
    }
  }
  public function word4Letter($letter) {
    return $this->{$letter};
  }
};

print $foo->word4Letter('a') . PHP_EOL; // Alpha
print $foo->word4Letter('b') . PHP_EOL; // Bravo
print $foo->word4Letter('c') . PHP_EOL; // Charlie
print $foo->word4Letter('d') . PHP_EOL; // Delta
print $foo->word4Letter('e') . PHP_EOL; // PHP Notice:  Undefined property

이 예에서는 $foo가 1개의 어레이 또는 stdClass를 컨스트럭터의 파라미터로만 사용하는 어나니머스 클래스로 초기화됩니다.

마지막으로 전달된 객체에 포함된 각 항목을 루프하여 객체의 속성에 동적으로 할당합니다.

이 접근 이벤트를 보다 범용적으로 만들기 위해 stdClass를 캐스팅할 수 있는 모든 클래스에서 구현할 인터페이스 또는 특성을 작성할 수 있습니다.

BTW: 시리얼라이즈된 경우 변환은 매우 중요합니다.주로 시리얼라이즈 해제에 의해 오브젝트의 타입이 해제되어 Date Time 오브젝트를 포함한 stdclass가 되기 때문입니다.

@Jadrovski의 예를 업데이트했습니다.이 예에서는 오브젝트와 어레이를 사용할 수 있게 되었습니다.

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

예시 배열

$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: (재귀적).그러나 배열에 따라 재귀적인지는 알 수 없습니다.추가 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;
            }
        }
    }
}

이를 배열로 변환하고 해당 배열의 첫 번째 요소를 반환하고 반환 매개 변수를 해당 클래스로 설정합니다.이제 해당 클래스가 stdclass가 아닌 해당 클래스로 재컨피규레이션되므로 해당 클래스에 대한 자동 완료를 얻어야 합니다.

/**
 * @return Order
 */
    public function test(){
    $db = new Database();

    $order = array();
    $result = $db->getConnection()->query("select * from `order` where productId in (select id from product where name = 'RTX 2070')");
    $data = $result->fetch_object("Order"); //returns stdClass
    array_push($order, $data);

    $db->close();
    return $order[0];
}

언급URL : https://stackoverflow.com/questions/3243900/convert-cast-an-stdclass-object-to-another-class