Intereting Posts

Преобразование / литье объекта stdClass в другой класс

Я использую стороннюю систему хранения, которая возвращает мне только объекты stdClass, независимо от того, что я питаю для какой-то неясной причины. Поэтому мне любопытно узнать, есть ли способ сбрасывать / преобразовывать объект stdClass в полноценный объект определенного типа.

Например, что-то вроде:

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

Я просто отбрасываю stdClass в массив и передаю его конструктору BusinessClass, но, возможно, есть способ восстановить исходный класс, о котором я не знаю.

Примечание. Меня не интересует тип ответов «Изменить систему хранения», поскольку это не представляет интереса. Пожалуйста, рассмотрите более академический вопрос о языковых возможностях.

ура

См. Руководство по типу Жонглирование на возможные слепки.

Разрешенными являются:

  • (int), (integer) – преобразование в целое число
  • (bool), (boolean) – отбрасывается в boolean
  • (float), (double), (real) – отбрасывается в float
  • (строка) – строка в строке
  • (массив) – преобразование в массив
  • (объект) – отбрасывается на объект
  • (unset) – отбрасывается до NULL (PHP 5)

Вам нужно будет написать Mapper, который выполняет кастинг из 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; } с /** * 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; } с /** * 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; } } }