recorrer array php stdclass

php - array - stdclass laravel



Convertir/lanzar un objeto stdClass a otra clase (7)

Estoy usando un sistema de almacenamiento de terceros que solo me devuelve objetos stdClass sin importar lo que publique por algún motivo oscuro. Así que tengo curiosidad por saber si hay una forma de convertir / convertir un objeto stdClass en un objeto completo de un tipo dado.

Por ejemplo, algo parecido a:

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

Simplemente estoy convirtiendo el stdClass en una matriz y alimentarlo al constructor BusinessClass, pero tal vez haya una manera de restaurar la clase inicial que no conozco.

Nota: No estoy interesado en el tipo de respuestas "Cambie su sistema de almacenamiento" ya que no es el punto de interés. Por favor, considere más una pregunta académica sobre las capacidades del lenguaje.

Aclamaciones


Consulte el manual sobre Tipo Malabares en posibles moldes.

Los moldes permitidos son:

  • (int), (entero) - emitido a entero
  • (bool), (boolean) - emitido a booleano
  • (flotar), (doble), (real) - lanzar a flotar
  • (cuerda) - lanzar a la cuerda
  • (matriz) - emitir a matriz
  • (objeto) - lanzar al objeto
  • (desarmado) - emitido a NULL (PHP 5)

Tendría que escribir un Mapper que realice el casting desde stdClass a otra clase concreta. No debería ser demasiado difícil de hacer.

O, si está de mal humor, podría adaptar el siguiente código:

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

que pseudobla una matriz a un objeto de una cierta clase. Esto funciona serializando primero la matriz y luego cambiando los datos serializados para que represente una cierta clase. El resultado se deserializa a una instancia de esta clase a continuación. Pero como dije, es hackish, así que espera efectos secundarios.

Para objeto a objeto, el código sería

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


Espero que alguien encuentre esto útil

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


Función modificada para fundición profunda (usando recursividad)

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


Para mover todas las propiedades existentes de un stdClass a un nuevo objeto de un nombre de clase especificado:

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

Uso:

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

Salida:

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

Esto es limitado debido al new operador ya que se desconoce qué parámetros necesitaría. Para su caso, probablemente sea apropiado.


Por cierto: la conversión es muy importante si se serializa, principalmente porque la deserialización rompe el tipo de objetos y se convierte en stdclass, incluidos los objetos DateTime.

Actualicé el ejemplo de @Jadrovski, ahora permite objetos y matrices.

ejemplo

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

matriz de ejemplo

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

código: (es recursivo). Sin embargo, no sé si es recursivo con matrices. Puede ser que falta un is_array extra

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


Puede usar la función anterior para fundir objetos de clase no similares (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; }

EJEMPLO:

class A { private $_x; } class B { public $_x; } $a = new A(); $b = new B(); $x = cast(''A'',$b); $x = cast(''B'',$a);


Tengo un problema muy similar. La solución de reflexión simplificada funcionó bien para mí:

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