Я использую стороннюю систему хранения, которая возвращает мне только объекты stdClass, независимо от того, что я питаю для какой-то неясной причины. Поэтому мне любопытно узнать, есть ли способ сбрасывать / преобразовывать объект stdClass в полноценный объект определенного типа.
Например, что-то вроде:
//$stdClass is an stdClass instance $converted = (BusinessClass) $stdClass;
Я просто отбрасываю stdClass в массив и передаю его конструктору BusinessClass, но, возможно, есть способ восстановить исходный класс, о котором я не знаю.
Примечание. Меня не интересует тип ответов «Изменить систему хранения», поскольку это не представляет интереса. Пожалуйста, рассмотрите более академический вопрос о языковых возможностях.
ура
См. Руководство по типу Жонглирование на возможные слепки.
Разрешенными являются:
Вам нужно будет написать 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; } } }