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

648

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

Мне нужна быстрая и грязная функция для преобразования объекта в массив.

Теги:
arrays

31 ответ

1103
Лучший ответ

Просто введите его

$array =  (array) $yourObject;

От http://www.php.net/manual/en/language.types.array.php

Если объект преобразуется в массив, результатом является массив, элементами которого являются свойства объекта. Ключи - это имена переменных-членов, с несколькими заметными исключениями: целочисленные свойства недоступны; частные переменные имеют имя класса, добавленное к имени переменной; защищенные переменные имеют "*", добавленные к имени переменной. Эти предварительные значения имеют нулевые байты с обеих сторон.

Пример: простой объект

$object = new StdClass;
$object->foo = 1;
$object->bar = 2;

var_dump( (array) $object );

Вывод:

array(2) {
  'foo' => int(1)
  'bar' => int(2)
} 

Пример: сложный объект

class Foo
{
    private $foo;
    protected $bar;
    public $baz;

    public function __construct()
    {
        $this->foo = 1;
        $this->bar = 2;
        $this->baz = new StdClass;
    }
}

var_dump( (array) new Foo );

Выход (с редактированием \0s для ясности):

array(3) {
  '\0Foo\0foo' => int(1)
  '\0*\0bar' => int(2)
  'baz' => class stdClass#2 (0) {}
}

Вывод с var_export вместо var_dump:

array (
  '' . "\0" . 'Foo' . "\0" . 'foo' => 1,
  '' . "\0" . '*' . "\0" . 'bar' => 2,
  'baz' => 
  stdClass::__set_state(array(
  )),
)

Указание этого способа не приведет к глубокому кастингу графа объектов, и вам необходимо применить нулевые байты (как описано в ручной цитате) для доступа к любым непубличным атрибутам. Таким образом, это лучше всего работает при бросании объектов или объектов StdClass только с общедоступными свойствами. Для быстрой и грязной (то, что вы просили) это хорошо.

Также см. это подробное сообщение в блоге:

  • 0
    Ха, и я уже нашел его применение - см. Мой ответ на stackoverflow.com/questions/4352203/…
  • 2
    Также рассмотрим интерфейс ArrayAccess , возможно, в сочетании с этим решением. php.net/manual/en/class.arrayaccess.php
Показать ещё 15 комментариев
275

Вы можете быстро преобразовать глубоко вложенные объекты в ассоциативные массивы, опираясь на поведение функций кодирования/декодирования JSON:

$array = json_decode(json_encode($nested_object), true);
  • 43
    Внимание, работает только для публичных членов вашего объекта ...
  • 9
    Это лучшее решение, если вы хотите рекурсивное преобразование на полную глубину (и, конечно, не возражаете против плохой производительности)
Показать ещё 9 комментариев
60

С первого хита Google для "php object to assoc array" мы имеем следующее:

function object_to_array($data)
{
    if (is_array($data) || is_object($data))
    {
        $result = array();
        foreach ($data as $key => $value)
        {
            $result[$key] = object_to_array($value);
        }
        return $result;
    }
    return $data;
}

Источник codesnippets.joyent.com.

  • 12
    Лично мне не нравится идея вызывать функцию для каждого значения. У меня есть похожая версия, но в 3 строки: function objectToArray($o) { $a = array(); foreach ($o as $k => $v) $a[$k] = (is_array($v) || is_object($v)) ? objectToArray($v): $v; return $a; } Это просто устанавливает все, что не является объектом или массивом, и продолжается без повторного вызова метода, если в этом нет необходимости.
  • 11
    @ SpYk3HH: напиши свой ответ?
Показать ещё 4 комментария
53

Если ваши свойства объекта общедоступны, вы можете:

$array =  (array) $object;

Если они являются частными или защищенными, у них будут имена странных ключей в массиве. Итак, в этом случае вам понадобится следующая функция:

function dismount($object) {
    $reflectionClass = new ReflectionClass(get_class($object));
    $array = array();
    foreach ($reflectionClass->getProperties() as $property) {
        $property->setAccessible(true);
        $array[$property->getName()] = $property->getValue($object);
        $property->setAccessible(false);
    }
    return $array;
}
  • 0
    Если ваша собственность защищена, setAccessible (false) изменит ее обратно на защищенную видимость? или это сделает его приватным?
  • 0
    Единственное решение, которое я нашел, это работало с защищенными свойствами. Спасибо
Показать ещё 4 комментария
18

Для многомерного массива

$array = json_decode(json_encode($objects),TRUE);
18

Просто используйте его для многомерного массива

$array = json_decode(json_encode($objects),TRUE);                  
12

Вместо написания сложных функций мы можем просто использовать встроенные функции PHP json_encode() и json_decode().

Сначала преобразуйте объект в JSON и верните его как массив.

json_decode() имеет второй параметр: возвратить ассоциативный массив, установить его в значение ИСТИНА.

$array = json_decode(json_encode($nested_object), true);
10
class Test{
    const A = 1;
    public $b = 'two';
    private $c = test::A;

    public function __toArray(){
        return call_user_func('get_object_vars', $this);
    }
}

$my_test = new Test();
var_dump((array)$my_test);
var_dump($my_test->__toArray());

Выход

array(2) {
    ["b"]=>
    string(3) "two"
    ["Testc"]=>
    int(1)
}
array(1) {
    ["b"]=>
    string(3) "two"
}
  • 0
    Плюсы и минусы этого решения? Как насчет класса, объявленного как класс Test {const A = 1; public $ parent = new Test (); }
10

Все остальные ответы, размещенные здесь, работают только с общедоступными атрибутами. Вот одно решение, которое работает с javabean-подобными объектами с использованием отражений и геттеров:

function entity2array($entity, $recursionDepth = 2) {
    $result = array();
    $class = new ReflectionClass(get_class($entity));
    foreach ($class->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
        $methodName = $method->name;
        if (strpos($methodName, "get") === 0 && strlen($methodName) > 3) {
            $propertyName = lcfirst(substr($methodName, 3));
            $value = $method->invoke($entity);

            if (is_object($value)) {
                if ($recursionDepth > 0) {
                    $result[$propertyName] = $this->entity2array($value, $recursionDepth - 1);
                } else {
                    $result[$propertyName] = "***";     //stop recursion
                }
            } else {
                $result[$propertyName] = $value;
            }
        }
    }
    return $result;
}
  • 0
    Да, но ... если вы используете Object / Array в качестве переменной, к чему все это приводит, зачем вам что-то кроме public свойств?
  • 0
    @ SpYk3HH: я не задавал вопрос. Я даже не знаю, почему кто-то предпочел бы массив массиву объекта.
Показать ещё 1 комментарий
7

Вот некоторый код:

function object_to_array($data) {
    if ((! is_array($data)) and (! is_object($data))) return 'xxx'; //$data;
    $result = array();

    $data = (array) $data;
    foreach ($data as $key => $value) {
        if (is_object($value)) $value = (array) $value;
        if (is_array($value)) 
        $result[$key] = object_to_array($value);
        else
            $result[$key] = $value;
    }

    return $result;
}
  • 0
    лучше всего работает для меня (но мне нужно было удалить 'xxx' и вернуть $ data)
6

Если вы не хотите, чтобы "*" добавлялся к вашему массиву, вы можете просто сделать что-то вроде

$json = json_encode($object);
$array = json_decode($json, true);
print_r($array);

Это работает отлично и намного лучше, чем приведение типов.

6

Как насчет get_object_vars($obj)? Кажется полезным, если вы хотите получить доступ к общедоступным свойствам объекта. http://www.php.net/function.get-object-vars

5

Чтобы преобразовать объект в массив, просто введите его явно

$name_of_array =  (array) $name_of_object;
4

Вы также можете создать функцию в PHP для преобразования массива объектов.

function object_to_array($object) {
    return (array) $object;
}
4

Вы можете легко использовать эту функцию, чтобы получить результат.

function objetToArray($adminBar){
      $reflector = new ReflectionObject($adminBar);
      $nodes = $reflector->getProperties();
      $out=[];
      foreach ($nodes as  $node) {
          $nod=$reflector->getProperty($node->getName());
          $nod->setAccessible(true);
          $out[$node->getName()]=$nod->getValue($adminBar);
      }
      return $out;
  }

использовать> = php5

4

Пользовательская функция для преобразования stdClass в массив:

function objectToArray($d) {
    if (is_object($d)) {
        // Gets the properties of the given object
        // with get_object_vars function
        $d = get_object_vars($d);
    }

    if (is_array($d)) {
        /*
        * Return array converted to object
        * Using __FUNCTION__ (Magic constant)
        * for recursive call
        */
        return array_map(__FUNCTION__, $d);
    } else {
        // Return array
        return $d;
    }
}

Другая настраиваемая функция для преобразования Array в stdClass:

function arrayToObject($d) {
    if (is_array($d)) {
        /*
        * Return array converted to object
        * Using __FUNCTION__ (Magic constant)
        * for recursive call
        */
        return (object) array_map(__FUNCTION__, $d);
    } else {
        // Return object
        return $d;
    }
}

Пример использования:

    // Create new stdClass Object
$init = new stdClass;

// Add some test data
$init->foo = "Test data";
$init->bar = new stdClass;
$init->bar->baaz = "Testing";
$init->bar->fooz = new stdClass;
$init->bar->fooz->baz = "Testing again";
$init->foox = "Just test";

// Convert array to object and then object back to array
$array = objectToArray($init);
$object = arrayToObject($array);

// Print objects and array
print_r($init);
echo "\n";
print_r($array);
echo "\n";
print_r($object);
4

Привет,

Вот моя рекурсивная функция PHP для преобразования объектов PHP в ассоциативный массив

// --------------------------------------------------------- 
// ----- object_to_array_recusive --- function (PHP) ------- 
// --------------------------------------------------------- 
// --- arg1: -- $object  =  PHP Object         - required --- 
// --- arg2: -- $assoc   =  TRUE or FALSE      - optional --- 
// --- arg3: -- $empty   =  '' (Empty String)  - optional ---
// --------------------------------------------------------- 
// ----- return: Array from Object --- (associative) ------- 
// --------------------------------------------------------- 

function object_to_array_recusive ( $object, $assoc=TRUE, $empty='' ) 
{ 

    $res_arr = array(); 

    if (!empty($object)) { 

        $arrObj = is_object($object) ? get_object_vars($object) : $object;

        $i=0; 
        foreach ($arrObj as $key => $val) { 
            $akey = ($assoc !== FALSE) ? $key : $i; 
            if (is_array($val) || is_object($val)) { 
                $res_arr[$akey] = (empty($val)) ? $empty : object_to_array_recusive($val); 
            } 
            else { 
                $res_arr[$akey] = (empty($val)) ? $empty : (string)$val; 
            } 

        $i++; 
        }

    } 

    return $res_arr;
}


// --------------------------------------------------------- 
// --------------------------------------------------------- 

Пример использования:

// ---- return associative array from object, ... use: 
$new_arr1 = object_to_array_recusive($my_object); 
// -- or -- 
// $new_arr1 = object_to_array_recusive($my_object,TRUE); 
// -- or -- 
// $new_arr1 = object_to_array_recusive($my_object,1); 


// ---- return numeric array from object, ... use: 
$new_arr2 = object_to_array_recusive($my_object,FALSE); 
  • 3
    .. или подписчик: $new_arr1 = (array) $my_object;
  • 1
    Версия oneliner мелкая, поэтому не эквивалентна.
4

Введите личный объект в массив.

$arr =  (array) $Obj;

Это решит вашу проблему.

  • 26
    Чем это отличается от принятого ответа?
  • 1
    Нет, не будет, если у вас есть частные или защищенные свойства.
Показать ещё 2 комментария
3

Прежде всего, если вам нужен массив из объекта, вы, вероятно, должны сначала представлять данные в виде массива. Думаю об этом.

Не используйте инструкции foreach или преобразования JSON. Если вы планируете это, снова вы работаете с структурой данных, а не с объектом.

Если вам действительно нужно, используйте ориентированный на объект подход, чтобы иметь чистый и основной код. Например:

Объект как массив

class PersonArray implements \ArrayAccess, \IteratorAggregate
{
    public function __construct(Person $person) {
        $this->person = $person;
    }
    // ...
 }

Если вам нужны все свойства, используйте объект передачи

class PersonTransferObject
{
    private $person;

    public function __construct(Person $person) {
        $this->person = $person;
    }

    public function toArray() {
        return [
            // 'name' => $this->person->getName();
        ];
    }

 }
3
function readObject($object) {
    $name = get_class ($object);
    $name = str_replace('\\', "\\\\", $name); \\ Comment this line, if you dont use class namespaces approach in your project
    $raw = (array)$object;

    $attributes = array();
    foreach ($raw as $attr => $val) {
        $attributes[preg_replace('('.$name.'|\*|)', '', $attr)] = $val;
    }
    return $attributes;
}

возвращает массив без специальных символов и имен классов

3

Возможно, вы захотите сделать это, когда вы получите данные как объекты из баз данных →

// Suppose result is the end product from some query $query

$result = $mysqli->query($query);
$result = db_result_to_array($result);

function db_result_to_array($result)
{
$res_array = array();

for ($count=0; $row = $result->fetch_assoc(); $count++)
    $res_array[$count] = $row;

    return $res_array;
}
  • 1
    Есть принятый ответ с 41 ответом, а не 1 или 10, 41. Что добавляет к нему ваш ответ?
2

Преобразование и удаление раздражающих звезд:

$array = (array) $object;
foreach($array as $key => $val)
{
   $new_array[str_replace('*_','',$key)] = $val;
}

Вероятно, это будет дешевле, чем использование отражений.

1

Также вы можете использовать Компонент Symfony Serializer

use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;

$serializer = new Serializer([new ObjectNormalizer()], [new JsonEncoder()]);
$array = json_decode($serializer->serialize($object, 'json'), true);
1

Краткое решение @SpYk3HH

function objectToArray($o)
{
    $a = array();
    foreach ($o as $k => $v)
        $a[$k] = (is_array($v) || is_object($v)) ? objectToArray($v): $v;

    return $a;
}
1

Некоторые помехи для кода "хорошо-knwon"

/*** mixed Obj2Array(mixed Obj)***************************************/ 
static public function Obj2Array($_Obj) {
    if (is_object($_Obj))
        $_Obj = get_object_vars($_Obj);
    return(is_array($_Obj) ? array_map(__METHOD__, $_Obj) : $_Obj);   
} // BW_Conv::Obj2Array

Обратите внимание: если функция является членом класса (например, выше), вы должны изменить __FUNCTION__ на __METHOD__

0

Там мое предложение, если у вас есть объекты в объектах даже с частными членами:

public function dismount($object) {
    $reflectionClass = new \ReflectionClass(get_class($object));
    $array = array();
    foreach ($reflectionClass->getProperties() as $property) {
        $property->setAccessible(true);
        if (is_object($property->getValue($object))) {
            $array[$property->getName()] = $this->dismount($property->getValue($object));
        } else {
            $array[$property->getName()] = $property->getValue($object);
        }
        $property->setAccessible(false);
    }
    return $array;
}
0

Используя typecasting, вы можете решить свою проблему. Просто добавьте следующие строки к возвращаемому объекту:

$arrObj = array(yourReturnedObject);

вы также можете добавить к нему новую пару ключей и значений, используя:

$arrObj['key'] = value;
0

Этот ответ является лишь объединением разных ответов этого сообщения, но это решение для преобразования объекта PHP с общедоступными или частными свойствами с простыми значениями или массивами в ассоциативном массиве...

function object_to_array($obj)
{
    if (is_object($obj)) $obj = (array)$this->dismount($obj);
    if (is_array($obj)) {
        $new = array();
        foreach ($obj as $key => $val) {
            $new[$key] = $this->object_to_array($val);
        }
    } else $new = $obj;
    return $new;
}

function dismount($object)
{
    $reflectionClass = new \ReflectionClass(get_class($object));
    $array = array();
    foreach ($reflectionClass->getProperties() as $property) {
        $property->setAccessible(true);
        $array[$property->getName()] = $property->getValue($object);
        $property->setAccessible(false);
    }
    return $array;
}
0

Поскольку многие люди находят этот поток из-за проблем с динамическим доступом к атрибутам объекта, я просто укажу, что вы можете сделать это в php: $valueRow->{"valueName"}

В контекстном режиме (удаленный вывод HTML для чтения):

$valueRows = json_decode("{...}"); // rows of unordered values decoded from a json-object

foreach($valueRows as $valueRow){

    foreach($references as $reference){

        if(isset($valueRow->{$reference->valueName})){
            $tableHtml .= $valueRow->{$reference->valueName};
        }else{
            $tableHtml .= " ";
        }

    }

}
0

Здесь я создал метод objectToArray(), который также работает с рекурсивными объектами, например, когда $objectA содержит $objectB, который снова указывает на $objectA.

Кроме того, я ограничил вывод публичными свойствами, используя ReflectionClass. Избавьтесь от него, если вам это не нужно.

    /**
     * Converts given object to array, recursively.
     * Just outputs public properties.
     *
     * @param object|array $object
     * @return array|string
     */
    protected function objectToArray($object) {
        if (in_array($object, $this->usedObjects, TRUE)) {
            return '**recursive**';
        }
        if (is_array($object) || is_object($object)) {
            if (is_object($object)) {
                $this->usedObjects[] = $object;
            }
            $result = array();
            $reflectorClass = new \ReflectionClass(get_class($this));
            foreach ($object as $key => $value) {
                if ($reflectorClass->hasProperty($key) && $reflectorClass->getProperty($key)->isPublic()) {
                    $result[$key] = $this->objectToArray($value);
                }
            }
            return $result;
        }
        return $object;
    }

Чтобы идентифицировать уже используемые объекты, я использую защищенное свойство в этом (абстрактном) классе с именем $this->usedObjects. Если найден рекурсивный вложенный объект, он будет заменен на строку **recursive**. В противном случае он потерпит неудачу из-за бесконечного цикла.

0
$Menu = new Admin_Model_DbTable_Menu(); 
$row = $Menu->fetchRow($Menu->select()->where('id = ?', $id));
$Addmenu = new Admin_Form_Addmenu(); 
$Addmenu->populate($row->toArray());
  • 0
    Я предполагаю, какой ответ для доктрины (или подобной) записи.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню