Saya menggunakan sistem penyimpanan pihak ketiga yang hanya mengembalikan objek stdClass apa pun yang saya berikan untuk beberapa alasan yang tidak jelas. Jadi saya penasaran untuk mengetahui apakah ada cara untuk mentransmisikan / mengonversi objek stdClass menjadi objek lengkap dari tipe tertentu.
Misalnya sesuatu di sepanjang baris:
//$stdClass is an stdClass instance
$converted = (BusinessClass) $stdClass;
Saya baru saja mentransmisikan stdClass ke dalam array dan memasukkannya ke konstruktor BusinessClass, tapi mungkin ada cara untuk mengembalikan kelas awal yang tidak saya sadari.
Catatan: Saya tidak tertarik dengan jenis jawaban 'Ubah sistem penyimpanan Anda' karena ini bukan poin yang menarik. Harap pertimbangkan ini lebih sebagai pertanyaan akademis tentang kemampuan bahasa.
Bersulang
PDOStatement::fetchObject
menyelesaikan tugas ini?Jawaban:
Lihat manual Type Juggling tentang kemungkinan cast.
Pemeran yang diizinkan adalah:
Anda harus menulis Mapper yang melakukan pengecoran dari stdClass ke kelas beton lainnya. Seharusnya tidak terlalu sulit untuk dilakukan.
Atau, jika Anda sedang dalam mood hackish, Anda dapat menyesuaikan kode berikut:
function arrayToObject(array $array, $className) { return unserialize(sprintf( 'O:%d:"%s"%s', strlen($className), $className, strstr(serialize($array), ':') )); }
yang melakukan pseudocast sebuah array ke objek dari kelas tertentu. Ini bekerja dengan terlebih dahulu membuat serial array dan kemudian mengubah data serial sehingga mewakili kelas tertentu. Hasilnya kemudian di-unserialized ke instance kelas ini. Tapi seperti yang saya katakan, itu hackish, jadi harapkan efek sampingnya.
Untuk objek ke objek, kodenya adalah
function objectToObject($instance, $className) { return unserialize(sprintf( 'O:%d:"%s"%s', strlen($className), $className, strstr(strstr(serialize($instance), '"'), ':') )); }
sumber
__PHP_Incomplete_Class
objek dengan menggunakan metode ini (setidaknya pada PHP 5.6).fooBar
(yang pribadi dariexample\Foo
dan yang umum dari stdClass). Sebaliknya itu menggantikan nilai.Anda dapat menggunakan fungsi di atas untuk mentransmisikan objek kelas yang tidak serupa (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; }
CONTOH:
class A { private $_x; } class B { public $_x; } $a = new A(); $b = new B(); $x = cast('A',$b); $x = cast('B',$a);
sumber
@Given the user :username has the id :id
fitur saya, dan menanganinya dengan refleksi di kelas konteks$destination = new $destination();
dapat ditukar dengan$destination = ( new ReflectionClass( $destination ) )->newInstanceWithoutConstructor();
jika Anda perlu menghindari pemanggilan konstruktor.Untuk memindahkan semua properti yang ada
stdClass
ke objek baru dari nama kelas yang ditentukan:/** * 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; }
Pemakaian:
$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);
Keluaran:
object(RestQuery)#2 (3) { ["action"]=> string(4) "auth" ["params"]=> &array(2) { [0]=> string(1) "h" [1]=> string(1) "n" } ["authKey"]=> string(32) "865c0c0b4ab0e063e5caa3387c1a8741" } NULL
Ini dibatasi karena
new
operator tidak diketahui parameter mana yang diperlukan. Untuk kasus Anda mungkin cocok.sumber
Saya memiliki masalah yang sangat mirip. Solusi refleksi yang disederhanakan bekerja dengan baik untuk saya:
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; }
sumber
Semoga seseorang menemukan ini berguna
// 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; }
sumber
Fungsi yang diubah untuk pengecoran dalam (menggunakan rekursi)
/** * 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; } } }
sumber
Dan pendekatan lain menggunakan pola dekorator dan pengambil & penyetel sihir 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);
sumber
pertimbangkan untuk menambahkan metode baru ke BusinessClass:
public static function fromStdClass(\stdClass $in): BusinessClass { $out = new self(); $reflection_object = new \ReflectionObject($in); $reflection_properties = $reflection_object->getProperties(); foreach ($reflection_properties as $reflection_property) { $name = $reflection_property->getName(); if (property_exists('BusinessClass', $name)) { $out->{$name} = $in->$name; } } return $out; }
maka Anda dapat membuat BusinessClass baru dari $ stdClass:
sumber
BTW: Konversi sangat penting jika Anda dibuat berseri, terutama karena de-serialisasi memecah jenis objek dan berubah menjadi stdclass, termasuk objek DateTime.
Saya memperbarui contoh @Jadrovski, sekarang memungkinkan objek dan array.
contoh
$stdobj=new StdClass(); $stdobj->field=20; $obj=new SomeClass(); fixCast($obj,$stdobj);
contoh larik
$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);
kode: (rekursifnya). Namun, saya tidak tahu apakah itu rekursif dengan array. Mungkin ada is_array tambahan yang hilang
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; } } } }
sumber
Namun pendekatan lain.
Berikut ini sekarang dimungkinkan berkat versi PHP 7 terbaru.
$theStdClass = (object) [ 'a' => 'Alpha', 'b' => 'Bravo', 'c' => 'Charlie', 'd' => 'Delta', ]; $foo = new class($theStdClass) { public function __construct($data) { if (!is_array($data)) { $data = (array) $data; } foreach ($data as $prop => $value) { $this->{$prop} = $value; } } public function word4Letter($letter) { return $this->{$letter}; } }; print $foo->word4Letter('a') . PHP_EOL; // Alpha print $foo->word4Letter('b') . PHP_EOL; // Bravo print $foo->word4Letter('c') . PHP_EOL; // Charlie print $foo->word4Letter('d') . PHP_EOL; // Delta print $foo->word4Letter('e') . PHP_EOL; // PHP Notice: Undefined property
Dalam contoh ini, $ foo sedang diinisialisasi sebagai kelas anonim yang mengambil satu array atau stdClass sebagai satu-satunya parameter untuk konstruktor.
Akhirnya, kami mengulang setiap item yang terdapat dalam objek yang diteruskan dan secara dinamis menetapkannya ke properti objek.
Untuk membuat acara pendekatan ini lebih umum, Anda dapat menulis antarmuka atau Sifat yang akan Anda implementasikan di kelas mana pun tempat Anda ingin mentransmisikan stdClass.
sumber
Ubah menjadi sebuah array, kembalikan elemen pertama dari array itu, dan setel parameter kembalian ke kelas itu. Sekarang Anda harus mendapatkan pelengkapan otomatis untuk kelas itu karena akan mengatur ulang sebagai kelas itu alih-alih stdclass.
/** * @return Order */ public function test(){ $db = new Database(); $order = array(); $result = $db->getConnection()->query("select * from `order` where productId in (select id from product where name = 'RTX 2070')"); $data = $result->fetch_object("Order"); //returns stdClass array_push($order, $data); $db->close(); return $order[0]; }
sumber