Веб

Как преобразовать PHP объект в ассоциативный массив

Как преобразовать PHP объект в ассоциативный массив: (array), рекурсивная функция и json_decode(json_encode()). Примеры, обработка DateTime и циклов. Советы.

Как преобразовать PHP объект в ассоциативный массив

Я интегрирую API на свой сайт, который работает с данными, хранящимися в объектах, в то время как мой код написан с использованием массивов. Мне нужна функция для преобразования PHP объектов в ассоциативные массивы.

Постановка проблемы

  • API возвращает данные в виде PHP объектов
  • Мой существующий код использует массивы для обработки данных
  • Необходимо преобразовывать объекты в массивы для совместимости

Требования

  • Ищу простую функцию для преобразования объектов в массивы
  • Решение должно обрабатывать вложенные объекты, если это возможно
  • Нужно сохранять отношения ключ-значение при преобразовании

Какой самый эффективный способ преобразовать PHP объект в ассоциативный массив в PHP?

Проще всего преобразовать PHP объект в ассоциативный массив (php to array) — привести объект к (array) для простых случаев; для вложенных структур лучше рекурсивная функция, сохраняющая отношения ключ‑значение. Быстрый хак — json_decode(json_encode($obj), true), но он теряет типы (DateTime, ресурсы), ломается на циклах и чувствителен к кодировке. Ниже — практичные примеры, готовая рекурсивная функция и рекомендации по выбору метода.


Содержание


Быстрый способ: приведение (array) — преобразовать объект в массив

Если вам нужно быстро преобразовать верхний уровень объекта в массив — используйте приведение (array). Просто, быстро, но поверхностно: вложенные объекты останутся объектами.

Пример:

php
$obj = (object) ['id' => 1, 'meta' => (object) ['author' => 'Ivan']];
$arr = (array) $obj;
// $arr['meta'] всё ещё stdClass
var_dump($arr);

Когда подходит

  • Простые ответы API без вложенных объектов.
  • Нужна скорость и минимум кода.

Ограничения


Рекурсивная функция — преобразовать объект в массив рекурсивно

Нужно сохранить вложенные структуры и ключ‑значение? Тогда рекурсивная функция — стандартный путь. Вот короткая и понятная реализация (на основе практик с StackOverflow и php.net):

php
function object_to_array_recursive($input, &$visited = []) {
 if (is_object($input)) {
 // Обрабатываем распространённые специальные объекты
 if ($input instanceof \DateTimeInterface) {
 return $input->format(\DateTime::ATOM);
 }
 if ($input instanceof \JsonSerializable) {
 $input = $input->jsonSerialize();
 } else {
 $oid = spl_object_hash($input);
 if (isset($visited[$oid])) {
 return null; // отметка рекурсии
 }
 $visited[$oid] = true;
 $input = get_object_vars($input); // возвращает массив свойств объекта
 }
 }

 if (is_array($input)) {
 $result = [];
 foreach ($input as $key => $val) {
 // убираем кодировку приватных/защищённых ключей "\0ClassName\0prop"
 $cleanKey = is_string($key) ? preg_replace('/^\0.*\0/', '', $key) : $key;
 $result[$cleanKey] = object_to_array_recursive($val, $visited);
 }
 return $result;
 }

 return $input; // скаляр, null или ресурс (можно обрабатывать отдельно)
}

Пояснения и ссылки:


JSON-подход (json_encode → json_decode)

Самый короткий код для глубокой конверсии:

php
$arr = json_decode(json_encode($obj), true);

Плюсы

  • Очень простая запись; рекурсивно переводит структуру.
  • Часто быстрее, чем простая рекурсия для больших массивов (но зависит от данных).

Минусы

Когда использовать

  • Когда структура простая и данные — чисто JSON‑совместимые (API обычно возвращают JSON‑совместимые объекты).
  • Быстрое прототипирование.

Краевые случаи: DateTime, приватные свойства, циклы, ресурсы

DateTime и похожие объекты

  • DateTime лучше явно форматировать: $dt->format(DATE_ATOM) или обрабатывать в рекурсии через instanceof \DateTimeInterface.

Приватные и защищённые свойства

  • get_object_vars (и приведение (array)) вернут ключи вида “\0ClassName\0property” для приватных/protected. Очищайте ключи регулярным выражением: preg_replace('/^\0.*\0/', '', $key).

Циклические ссылки

  • Чтобы не попасть в бесконечную рекурсию, отслеживайте посещённые объекты через spl_object_hash (см. пример выше). Альтернатива — SplObjectStorage.

Ресурсы и нестандартные типы

  • Ресурсы нельзя корректно сериализовать в массив; обычно возвращают null или идентификатор ресурса в строковом виде.
  • JSON‑метод ломается при не‑UTF8. Подробный разбор: https://gist.github.com/victorbstan/744478

Дополнительная обработка


Полный пример: безопасная рекурсивная функция

Вот более полный вариант с защитой от рекурсии и обработкой распространённых случаев:

php
function obj_to_array_safe($input, &$visited = [], $depth = 0, $maxDepth = 512) {
 if ($depth > $maxDepth) {
 return null; // защита от слишком глубокой рекурсии
 }

 if (is_object($input)) {
 if ($input instanceof \DateTimeInterface) {
 return $input->format(\DateTime::ATOM);
 }
 if ($input instanceof \JsonSerializable) {
 $input = $input->jsonSerialize();
 } else {
 $oid = spl_object_hash($input);
 if (isset($visited[$oid])) {
 return ['__recursion' => true];
 }
 $visited[$oid] = true;
 $input = get_object_vars($input);
 }
 }

 if (is_array($input)) {
 $out = [];
 foreach ($input as $k => $v) {
 $cleanKey = is_string($k) ? preg_replace('/^\0.*\0/', '', $k) : $k;
 $out[$cleanKey] = obj_to_array_safe($v, $visited, $depth + 1, $maxDepth);
 }
 return $out;
 }

 if (is_resource($input)) {
 return null;
 }

 return $input;
}

// Использование:
$array = obj_to_array_safe($apiResponse);

Ещё вариант: сначала проверить, есть ли у объекта метод toArray (часто в библиотеках и моделях):

php
if (method_exists($obj, 'toArray')) {
 $array = $obj->toArray();
} else {
 $array = obj_to_array_safe($obj);
}

Советы по производительности и выбору метода

Какой способ выбрать?

  • Нужна скорость и структура неглубока — (array) (приведение).
  • Нужна корректная обработка вложенных структур и особых типов — рекурсивная функция (предпочтительно).
  • Быстро и удобно для JSON‑совместимых данных — json_decode(json_encode(...), true) (но помните про потерю типов и кодировку).

Дополнительные рекомендации

  • Для больших ответов API сравните по производительности: json vs рекурсия — всё зависит от структуры данных; блог и Gist обсуждают производительность и ограничения (см. https://ben.lobaugh.net/blog/567/php-recursively-convert-an-object-to-an-array и https://gist.github.com/victorbstan/744478).
  • Если используете фреймворк — проверьте стандартные методы (toArray, getArrayCopy для ArrayObject).
  • После конверсии применяйте array_walk_recursive для финальной нормализации значений, если нужно.

Источники


Заключение

Если цель — просто и быстро преобразовать объект в массив, начните с (array); для надёжной конверсии вложенных структур используйте рекурсивную функцию (или финальный пример выше). Быстрый способ через json_decode(json_encode(...), true) удобен, но он не сохраняет типы и чувствителен к циклам и кодировке. В большинстве интеграций API оптимальным будет рекурсивный подход, который корректно преобразует stdClass в ассоциативные массивы и сохраняет отношения ключ‑значение.

Авторы
Проверено модерацией
Модерация