모호한 이유로 무엇을 공급하든 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);