Konvertieren / Umwandeln eines stdClass-Objekts in eine andere class

Ich benutze ein Drittanbieter-Speichersystem, das mir nur stdClass-Objekte zurückgibt, egal, was ich aus irgendeinem obskuren Grund einspeise. Ich bin neugierig zu wissen, ob es eine Möglichkeit gibt, ein stdClass-Objekt in ein vollwertiges Objekt eines bestimmten Typs zu konvertieren.

Zum Beispiel etwas in der Art von:

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

Ich werfe nur die stdClass in ein Array und füttere es dem BusinessClass-Konstruktor, aber vielleicht gibt es eine Möglichkeit, die ursprüngliche class wiederherzustellen, die mir nicht bekannt ist.

Hinweis: Ich bin nicht daran interessiert, die Art von Antworten zu ändern, da dies nicht von Interesse ist. Bitte betrachte es eher als eine akademische Frage zu den Sprachfähigkeiten.

Prost

    Siehe das Handbuch zum Typ Jonglieren bei möglichen Würfen.

    Die erlaubten Formen sind:

    • (int), (Ganzzahl) – In Ganzzahl umgewandelt
    • (bool), (boolean) – in Boolean umgewandelt
    • (float), (double), (real) – zum float casting
    • (Zeichenkette) – In Zeichenkette umwandeln
    • (array) – In Array konvertieren
    • (Objekt) – zum Objekt casting
    • (Unset) – Umwandlung in NULL (PHP 5)

    Sie müssten einen Mapper schreiben , der die Umwandlung von stdClass in eine andere konkrete class durchführt. Sollte nicht zu schwer zu tun sein.

    Oder, wenn Sie in einer hashigen Stimmung sind, könnten Sie den folgenden Code anpassen:

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

    welches ein Array auf ein Objekt einer bestimmten class wirft. Dies funktioniert, indem zuerst das Array serialisiert wird und dann die serialisierten Daten geändert werden, so dass es eine bestimmte class darstellt. Das Ergebnis wird dann zu einer Instanz dieser class unserialisiert. Aber wie ich schon sagte, es ist hackisch, also erwarte Nebenwirkungen.

    Für Objekt zu Objekt wäre der Code

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

    Sie können die obige function zum Umwandeln nicht ähnlicher classnobjekte verwenden (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; } 

    BEISPIEL:

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

    So verschieben Sie alle vorhandenen Eigenschaften einer stdClass in ein neues Objekt eines angegebenen classnnamens:

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

    Verwendung:

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

    Ausgabe:

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

    Dies ist aufgrund des new Operators begrenzt, da nicht bekannt ist, welche Parameter benötigt werden. Für Ihren Fall wahrscheinlich passend.

    Ich habe ein sehr ähnliches Problem. Vereinfachte Reflektionslösung hat für mich gut funktioniert:

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

    Hoffe, dass jemand das nützlich findet

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

    Geänderte function für das Tiefcasting (mit Rekursion)

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

    BTW: Konvertieren ist sehr wichtig, wenn Sie serialisiert werden, hauptsächlich weil die Deserialisierung den Objekttyp unterbricht und in stdclass umgewandelt wird, einschließlich DateTime-Objekten.

    Ich habe das Beispiel von @Jadrovski aktualisiert, jetzt erlaubt es Objekte und Arrays.

    Beispiel

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

    Beispiel-Array

     $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: (es ist rekursiv). Ich weiß jedoch nicht, ob es mit Arrays rekursiv ist. Möglicherweise fehlt ein extra 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; } } } }