Есть ли способ конвертировать многомерный объект array
в объект stdClass
в PHP?
Кастинг как (object)
не работает рекурсивно. json_decode(json_encode($array))
дает результат, который я ищу, но должен быть лучший способ...
Есть ли способ конвертировать многомерный объект array
в объект stdClass
в PHP?
Кастинг как (object)
не работает рекурсивно. json_decode(json_encode($array))
дает результат, который я ищу, но должен быть лучший способ...
Насколько я могу судить, для этого нет заранее подготовленного решения, поэтому вы можете просто сворачивать свой собственный:
function array_to_object($array) {
$obj = new stdClass;
foreach($array as $k => $v) {
if(strlen($k)) {
if(is_array($v)) {
$obj->{$k} = array_to_object($v); //RECURSION
} else {
$obj->{$k} = $v;
}
}
}
return $obj;
}
Я знаю, что этот ответ приходит поздно, но я отправлю его всем, кто ищет решение.
Вместо всего этого цикла и т.д. вы можете использовать функцию PHP json_ *. У меня есть несколько удобных функций, которые я использую много.
/**
* Convert an array into a stdClass()
*
* @param array $array The array we want to convert
*
* @return object
*/
function arrayToObject($array)
{
// First we convert the array to a json string
$json = json_encode($array);
// The we convert the json string to a stdClass()
$object = json_decode($json);
return $object;
}
/**
* Convert a object to an array
*
* @param object $object The object we want to convert
*
* @return array
*/
function objectToArray($object)
{
// First we convert the object into a json string
$json = json_encode($object);
// Then we convert the json string to an array
$array = json_decode($json, true);
return $array;
}
Надеюсь, это будет полезно
function toObject($array) {
$obj = new stdClass();
foreach ($array as $key => $val) {
$obj->$key = is_array($val) ? toObject($val) : $val;
}
return $obj;
}
/**
* Recursively converts associative arrays to stdClass while keeping integer keys subarrays as arrays
* (lists of scalar values or collection of objects).
*/
function a2o( array $array ) {
$resultObj = new \stdClass;
$resultArr = array();
$hasIntKeys = false;
$hasStrKeys = false;
foreach ( $array as $k => $v ) {
if ( !$hasIntKeys ) {
$hasIntKeys = is_int( $k );
}
if ( !$hasStrKeys ) {
$hasStrKeys = is_string( $k );
}
if ( $hasIntKeys && $hasStrKeys ) {
$e = new \Exception( 'Current level has both integer and string keys, thus it is impossible to keep array or convert to object' );
$e->vars = array( 'level' => $array );
throw $e;
}
if ( $hasStrKeys ) {
$resultObj->{$k} = is_array( $v ) ? a2o( $v ) : $v;
} else {
$resultArr[$k] = is_array( $v ) ? a2o( $v ) : $v;
}
}
return ($hasStrKeys) ? $resultObj : $resultArr;
}
Некоторые из других решений, размещенных здесь, не могут отличить последовательные массивы (что было бы []
в JS) от карт ({}
в JS.) Для многих случаев использования важно рассказать обо всех PHP-массивах, которые имеют все последовательные числовые ключи, которые должны быть оставлены как таковые, из массивов PHP, которые не имеют числовых ключей, которые должны быть преобразованы в объекты. (Мои решения ниже undefined для массивов, которые не попадают в две вышеуказанные категории.)
Метод json_decode(json_encode($x))
корректно обрабатывает два типа, но не является самым быстрым решением. Тем не менее, он по-прежнему приличный, всего 25 мкс за каждый прогон на мои данные образца (усредненный за 1М пробегов, минус накладные расходы цикла).
Я сравнил пару вариаций рекурсивного конвертера и получил следующее. Он восстанавливает все массивы и объекты (выполняет глубокую копию), но, кажется, быстрее, чем альтернативные решения, которые изменяют массивы на месте. Он синхронизируется с 11μs за выполнение по моим данным образца:
function array_to_object($x) {
if (!is_array($x)) {
return $x;
} elseif (is_numeric(key($x))) {
return array_map(__FUNCTION__, $x);
} else {
return (object) array_map(__FUNCTION__, $x);
}
}
Вот версия на месте. Это может быть быстрее на некоторых больших входных данных, где нужно преобразовать только мелкие части, но по моим образцам данных он выполнял 15 мкс за выполнение:
function array_to_object_inplace(&$x) {
if (!is_array($x)) {
return;
}
array_walk($x, __FUNCTION__);
reset($x);
if (!is_numeric(key($x))) {
$x = (object) $x;
}
}
Я не тестировал решения, используя array_walk_recursive()
Поздно, но просто хотелось упомянуть, что вы можете использовать кодировку/декодирование JSON для полного преобразования из/в массив:
//convert object $object into array
$array = json_decode(json_encode($object), true);
//convert array $array into object
$object = json_decode(json_encode($array));
Функции json_encode и json_decode доступны начиная с php 5.2
Здесь вы можете выполнить преобразование массива в место на месте, использующее внутренний (неглубокий) внутренний механизм ввода-вывода типа "массив-объект". Он создает новые объекты только при необходимости, сводя к минимуму дублирование данных.
function toObject($array) {
foreach ($array as $key=>$value)
if (is_array($value))
$array[$key] = toObject($value);
return (object)$array;
}
Предупреждение - не используйте этот код, если существует риск иметь круглые ссылки.
EDIT: Эта функция является преобразованием из объекта в массив.
От https://forrst.com/posts/PHP_Recursive_Object_to_Array_good_for_handling-0ka
protected function object_to_array($obj)
{
$arrObj = is_object($obj) ? get_object_vars($obj) : $obj;
foreach ($arrObj as $key => $val) {
$val = (is_array($val) || is_object($val)) ? $this->object_to_array($val) : $val;
$arr[$key] = $val;
}
return $arr;
}
Вот гладкий способ сделать это, который может обрабатывать ассоциативный массив с большой глубиной и не перезаписывать свойства объекта, которые не находятся в массиве.
<?php
function setPropsViaArray( $a, $o )
{
foreach ( $a as $k => $v )
{
if ( is_array( $v ) )
{
$o->{$k} = setPropsViaArray( $v, ! empty ( $o->{$k} ) ? $o->{$k} : new stdClass() );
}
else
{
$o->{$k} = $v;
}
}
return $o;
};
setPropsViaArray( $newArrayData, $existingObject );
Самое короткое, что я мог бы придумать:
array_walk_recursive($obj, function (&$val) { if (is_object($val)) $val = get_object_vars($val); });
Вы можете использовать array_map
рекурсивно:
public static function _arrayToObject($array) {
return is_array($array) ? (object) array_map([__CLASS__, __METHOD__], $array) : $array;
}
Прекрасно подходит для меня, поскольку он не отображает, например, углеродные объекты в базовый stdClass (который кодируется/декодирует json)