Как преобразовать массив в объект в PHP?


367

Как я могу преобразовать такой массив в объект?

[128] => Array
    (
        [status] => Figure A.
 Facebook's horizontal scrollbars showing up on a 1024x768 screen resolution.
    )

[129] => Array
    (
        [status] => The other day at work, I had some spare time
    )

4
Какой именно объект вы хотите получить? Что я имею в виду: какими должны быть атрибуты?
Паскаль МАРТИН

в цикле должны оба, потому что статус - это один массив данных, поэтому оба являются printet
streetparade

не уверен, когда, но это просто работает:$a = (object)['hello' => 'world'];
Nishchal Gautam

Ответы:


588

В простейшем случае, вероятно, достаточно «привести» массив в качестве объекта:

$object = (object) $array;

Другой вариант - создать экземпляр стандартного класса в качестве переменной и выполнить цикл по массиву, переназначая значения:

$object = new stdClass();
foreach ($array as $key => $value)
{
    $object->$key = $value;
}

Как отметил Эдсон Медина , действительно чистым решением является использование встроенных json_функций:

$object = json_decode(json_encode($array), FALSE);

Это также (рекурсивно) преобразует все ваши вложенные массивы в объекты, которые вы можете или не хотите. К сожалению, он имеет 2-3-кратное снижение производительности по сравнению с циклическим подходом.

Предупреждение! (спасибо Ultra за комментарий):

json_decode в разных средах преобразует данные UTF-8 по-разному. В итоге я получаю значения «240,00» на месте и «240» на производстве - огромный разбойник. Более того, если преобразование не удалось, строка get возвращается как NULL


41
«поскольку переменные не могут начинаться с цифр», да, они могут: $ object -> {3} = 'xyz';
Chelmertz

11
«имеет 2-3-кратное снижение производительности». Это несправедливое сравнение, поскольку последний метод возвращает рекурсивные объекты, а циклический подход без дополнительных условий (как в ответе @streetparade) конвертирует только первый уровень.
Feeela

8
@feeela Я не думаю, что это несправедливо вообще. Я упоминал, что это делает рекурсивное преобразование. Кроме того, в 2-3 раза было достигнуто снижение производительности при использовании плоского входного массива (который не использовал бы рекурсию)
jlb

6
ПРЕДУПРЕЖДЕНИЕ! json_decode в разных средах преобразует данные UTF-8 по-разному. В итоге я получаю значения «240,00» на месте и «240» на производстве - огромный разбойник. Morover, если преобразование не выполнено, строка get возвращается как NULL
Szymon Toda

1
Обратите внимание, что при использовании функций json_ * ссылки (например, на другие массивы), хранящиеся в исходном массиве, в этом случае будут дублироваться. Скажем, ключ xв массиве содержит ссылку на другой массив. Тогда $object->xпосле выполнения вашего однострочного будет дубликат $array['x'], а не ссылка на исходный массив. Это может быть безвредно в некоторых приложениях, но для больших массивов это тратит впустую память и может испортить выполнение, если ссылка используется позже.
Копролал

153

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

// *convert array to object* Array([id]=> 321313[username]=>shahbaz)
$object = (object) $array_name;

//now it is converted to object and you can access it.
echo $object->username;

107

Простой способ был бы

$object = (object)$array;

Но это не то, что вы хотите. Если вам нужны объекты, вы хотите чего-то достичь, но этого нет в этом вопросе. Использование объектов только по причине использования объектов не имеет смысла.


2
не работает, я сделал это, прежде чем задал вопрос здесь, так что должен быть другой способ сделать это
streetparade

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

хм .. я посмотрел на вывод браузера, он выглядит как этот объект (stdClass) # 150 (130) {[0] => array (1) {["status"] => string (130) "Наконец-то Mac и Пользователям Linux не нужно чувствовать себя гражданами второго сорта на земле Chrome: у них есть официальная бета-версия… "} официально, это объект, но как выполнить итерацию, бросить это, чтобы я мог получить статус, такой как $ obj-> status любой идеи ?
Streetparade

zombat, кодирование JSON - это не причина для использования объекта, для использования объектов есть флаг в json_encode (). при сериализации нужен конкретный тип объекта, ожидаемый получателем. И вообще я стараюсь помочь с актуальной проблемой. для меня этот вопрос подразумевает, что есть архитектурная ошибка где-то еще.
Йоханнес

хороший, работа с массивом laravel для объекта проблема
Энтони Кал

105

Быстрый взлом:

// assuming $var is a multidimensional array
$obj = json_decode (json_encode ($var), FALSE);

Не красиво, но работает.


2
Я на самом деле люблю это решение, использование встроенных функций вместо пользовательских всегда быстрее, и это прекрасно работает. Спасибо за совет.
августа

@Oddant Это решает проблему, упомянутую выше (преобразовать массив в объект). Ваша напыщенная речь должна быть направлена ​​в основной пост, а не в мое решение.
Эдсон Медина

@EdsonMedina Я сделал, мой пост слишком вниз, хотя.
августа

1
@Oddant, чтобы быть справедливым по отношению к @EdsonMedina, оригинальный вопрос не определяет, какая видимость нужна атрибутам, и, поскольку OP не использует $this в комментариях, которые следуют в качестве средства доступа, подразумевается, что он / она желает получить stdClassэкземпляр в качестве вывода, а не пользовательский класс, такой как ваш ответ. Я согласен с элегантностью этого решения, но, к сожалению, это довольно часто используемый шаблон для решения этой проблемы с вложенными массивами, где приведение к объекту не будет работать. Также возможно, что OP использует интерфейс, который требует и объект в качестве ввода, а не массив.
DeaconDesperado

3
Не забывайте, что таким образом вы потеряете все, кроме основных типов. Например, DateTime будет конвертером stdObject.
Денис Пшенов

97

Вот три способа:

  1. Поддельный реальный объект:

    class convert
    {
        public $varible;
    
        public function __construct($array)
        {
            $this = $array;
        }
    
        public static function toObject($array)
        {
            $array = new convert($array);
            return $array;
        }
    }
  2. Преобразуйте массив в объект, приведя его к объекту:

    $array = array(
        // ...
    );
    $object = (object) $array;
  3. Вручную преобразовать массив в объект:

    $object = object;
    foreach ($arr as $key => $value) {
        $object->{$key} = $value;
    }

2
хм, спасибо, но ваш класс лица выдает следующую ошибку. Неустранимая ошибка: Невозможно переназначить $ this в /var/www/bot/inc/twitter-bot.php в строке 10
streetparade

1
и typcasint @ reference не очень хорошая идея, даже если это не сработает, вот что я получил неожиданно T_OBJECT_CAST, ожидая T_NEW или T_STRING или T_VARIABLE или '$'
streetparade

2
$ array = & (object) $ array == хорошая реализация KISS!
mate64

16
Почему кто-то хочет использовать метод, отличный от 2)? Есть ли минусы?
Йогу

7
вставка массива в объект не работает на вложенных массивах
minhajul

34

Это простой способ, он также создаст объект для рекурсивных массивов:

$object = json_decode(json_encode((object) $yourArray), FALSE);

4
переход falseк json_decode()вернет ассоциативный массив.
Rust

3
@ user3284463 Передача trueto json_decodeвозвращает ассоциативный массив, falseявляется значением по умолчанию и возвращает StdClassэкземпляр.
Эллиот Рид

24

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

Например: просто введите его

$object =  (object) $yourArray;

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

/**
 * dereference a value and optionally setting its type
 *
 * @param mixed $mixed
 * @param null  $type (optional)
 *
 * @return mixed $mixed set as $type
 */
function rettype($mixed, $type = NULL) {
    $type === NULL || settype($mixed, $type);
    return $mixed;
}

Пример использования в вашем случае ( Online Demo ):

$yourArray = Array('status' => 'Figure A. ...');

echo rettype($yourArray, 'object')->status; // prints "Figure A. ..."

17

Этот работал для меня

  function array_to_obj($array, &$obj)
  {
    foreach ($array as $key => $value)
    {
      if (is_array($value))
      {
      $obj->$key = new stdClass();
      array_to_obj($value, $obj->$key);
      }
      else
      {
        $obj->$key = $value;
      }
    }
  return $obj;
  }

function arrayToObject($array)
{
 $object= new stdClass();
 return array_to_obj($array,$object);
}

Применение :

$myobject = arrayToObject($array);
print_r($myobject);

возвращает:

    [127] => stdClass Object
        (
            [status] => Have you ever created a really great looking website design
        )

    [128] => stdClass Object
        (
            [status] => Figure A.
 Facebook's horizontal scrollbars showing up on a 1024x768 screen resolution.
        )

    [129] => stdClass Object
        (
            [status] => The other day at work, I had some spare time
        )

как обычно, вы можете сделать это как:

foreach($myobject as $obj)
{
  echo $obj->status;
}

Но это примерно на 500% медленнее (проверено), чем приведение типов: $ obj = (object) $ array;
xZero

@xZero, но $obj = (object) $array;не работает для многомерных массивов.
Джефф

15

Насколько я знаю, встроенного метода для этого не существует, но это так же просто, как простой цикл:

    $obj= new stdClass();

    foreach ($array as $k=> $v) {
        $obj->{$k} = $v;
    }

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


15

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

$arr= [128=> ['status'=>
                 'Figure A. Facebook \'s horizontal scrollbars showing up on a 1024x768 screen resolution.'],
                  129=>['status'=>'The other day at work, I had some spare time']];

            $ArrToObject=(object)$arr;
            var_dump($ArrToObject);

Результатом будет объект, который содержит массивы:

object (stdClass) # 1048 (2) {[128] => array (1) {

["status"] => string (87) "Рисунок A. Горизонтальные полосы прокрутки Facebook, показывающие разрешение экрана 1024x768." }

[129] => array (1) {["status"] => string (44) "На днях на работе у меня было свободное время"}}


9

На самом деле, если вы хотите использовать это с многомерными массивами, вы захотите использовать некоторую рекурсию.

static public function array_to_object(array $array)
{
    foreach($array as $key => $value)
    {
        if(is_array($value))
        {
            $array[$key] = self::array_to_object($value);
        }
    }
    return (object)$array;
}

8

Я бы определенно пошел с чистым путем, как это:

<?php

class Person {

  private $name;
  private $age;
  private $sexe;

  function __construct ($payload)
  {
     if (is_array($payload))
          $this->from_array($payload);
  }


  public function from_array($array)
  {
     foreach(get_object_vars($this) as $attrName => $attrValue)
        $this->{$attrName} = $array[$attrName];
  }

  public function say_hi ()
  {
     print "hi my name is {$this->name}";
  }
}

print_r($_POST);
$mike = new Person($_POST);
$mike->say_hi();

?>

если вы отправите:

Formulaire

вы получите это:

Майк

Я нашел это более логичным, сравнивая приведенные выше ответы от Объектов, которые должны использоваться для цели, для которой они были созданы (инкапсулированные милые маленькие объекты).

Также использование get_object_vars гарантирует, что в манипулируемом объекте не будет создано никаких дополнительных атрибутов (вам не нужен автомобиль с фамилией, а также человек, ведущий себя на 4 колесах).


Почему бы вам не использовать $ attr_value вместо $ array [$ attr_name]; в вашей публичной функции from_array ($ array) function
Sakkeer Hussain

7

Вы также можете использовать ArrayObject, например:

<?php
    $arr = array("test",
                 array("one"=>1,"two"=>2,"three"=>3), 
                 array("one"=>1,"two"=>2,"three"=>3)
           );
    $o = new ArrayObject($arr);
    echo $o->offsetGet(2)["two"],"\n";
    foreach ($o as $key=>$val){
        if (is_array($val)) {
            foreach($val as $k => $v) {
               echo $k . ' => ' . $v,"\n";
            }
        }
        else
        {
               echo $val,"\n";
        }
    }
?>

//Output:
  2
  test
  one => 1
  two => 2
  three => 3
  one => 1
  two => 2
  three => 3

1
На мой взгляд, это должно стать лучшим ответом. Больше информации herre: php.net/manual/en/arrayobject.construct.php
Джулиан

7

Тот, который я использую (это член класса):

const MAX_LEVEL = 5; // change it as needed

public function arrayToObject($a, $level=0)
{

    if(!is_array($a)) {
        throw new InvalidArgumentException(sprintf('Type %s cannot be cast, array expected', gettype($a)));
    }

    if($level > self::MAX_LEVEL) {
        throw new OverflowException(sprintf('%s stack overflow: %d exceeds max recursion level', __METHOD__, $level));
    }

    $o = new stdClass();
    foreach($a as $key => $value) {
        if(is_array($value)) { // convert value recursively
            $value = $this->arrayToObject($value, $level+1);
        }
        $o->{$key} = $value;
    }
    return $o;
}

7

Немного сложная, но легко расширяемая техника:

Предположим, у вас есть массив

$a = [
     'name' => 'ankit',
     'age' => '33',
     'dob' => '1984-04-12'
];

Предположим, у вас есть класс Person, который может иметь больше или меньше атрибутов из этого массива. например

class Person 
{
    private $name;
    private $dob;
    private $age;
    private $company;
    private $city;
}

Если вы все еще хотите изменить свой массив на объект person. Вы можете использовать ArrayIterator Class.

$arrayIterator = new \ArrayIterator($a); // Pass your array in the argument.

Теперь у вас есть объект-итератор.

Создайте класс, расширяющий класс FilterIterator; где вы должны определить абстрактный метод принять. Следовать примеру

class PersonIterator extends \FilterIterator
{
    public function accept()
    {
        return property_exists('Person', parent::current());
    }
}

Вышеуказанная имплементация будет связывать свойство, только если оно существует в классе.

Добавьте еще один метод в классе PersonIterator

public function getObject(Person $object)
{
        foreach ($this as $key => $value)
        {
            $object->{'set' . underscoreToCamelCase($key)}($value);
        }
        return $object;
}

Убедитесь, что в вашем классе определены мутаторы. Теперь вы готовы вызывать эти функции там, где вы хотите создать объект.

$arrayiterator = new \ArrayIterator($a);
$personIterator = new \PersonIterator($arrayiterator);

$personIterator->getObject(); // this will return your Person Object. 

6

рекурсия твой друг

function __toObject(Array $arr) {
    $obj = new stdClass();
    foreach($arr as $key=>$val) {
        if (is_array($val)) {
            $val = __toObject($val);
        }
        $obj->$key = $val;
    }

    return $obj;
}

6

Для этого требуется PHP7, потому что я решил использовать лямбда-функцию для блокировки 'innerfunc' внутри основной функции. Лямбда-функция вызывается рекурсивно, поэтому необходимо: «использовать (& $ innerfunc)». Вы можете сделать это в PHP5, но не можете скрыть innerfunc.

function convertArray2Object($defs) {
    $innerfunc = function ($a) use ( &$innerfunc ) {
       return (is_array($a)) ? (object) array_map($innerfunc, $a) : $a; 
    };
    return (object) array_map($innerfunc, $defs);
}

5

используйте эту функцию, которую я сделал:

function buildObject($class,$data){
    $object = new $class;
    foreach($data as $key=>$value){
        if(property_exists($class,$key)){
            $object->{'set'.ucfirst($key)}($value);
        }
    }
    return $object;
}

Применение:

$myObject = buildObject('MyClassName',$myArray);

5

один лайнер

$object= json_decode(json_encode($result_array, JSON_FORCE_OBJECT));

1
Обратите внимание, что ссылки (например, на другие массивы), хранящиеся в исходном массиве, будут дублироваться этим однострочником. Скажем, ключ xв массиве содержит ссылку на другой массив. Тогда $object->xпосле выполнения вашего однострочного будет дубликат $result_array['x'], а не идентичный массив.
Копролал

4

Легко:

$object = json_decode(json_encode($array));

Пример:

$array = array(
    'key' => array(
        'k' => 'value',
    ),
    'group' => array('a', 'b', 'c')
);

$object = json_decode(json_encode($array));

Тогда верно следующее:

$object->key->k === 'value';
$object->group === array('a', 'b', 'c')

1
Я думаю, что это обходной путь. Зачем кодировать массив в JSON, а затем декодировать его? Это не оптимальное решение для меня.
Джулиан

1
@Julian, потому что он работает рекурсивно, делает это правильно и достаточно надежно («стандартно»), а также достаточно быстро, чтобы быть хорошей альтернативой случайной закодированной вручную магии обезьян.
СЗ

3

Вы также можете сделать это, добавив (объект) слева от переменной, чтобы создать новый объект.

<?php
$a = Array
    ( 'status' => " text" );
var_dump($a);
$b = (object)$a;
var_dump($b);
var_dump($b->status);

http://codepad.org/9YmD1KsU


1
возможно, стоит упомянуть, что это называется «приведение» или «приведение типа»: php.net/manual/en/… а поведение (object) array () описано
Пит

2

Использование json_encodeпроблематично из-за способа обработки данных не в формате UTF-8. Стоит отметить, что метод json_encode/ json_encodeтакже оставляет неассоциативные массивы в виде массивов. Это может или не может быть то, что вы хотите. Недавно я был вынужден воссоздать функциональность этого решения, но без использования json_функций. Вот что я придумал:

/**
 * Returns true if the array has only integer keys
 */
function isArrayAssociative(array $array) {
    return (bool)count(array_filter(array_keys($array), 'is_string'));
}

/**
 * Converts an array to an object, but leaves non-associative arrays as arrays. 
 * This is the same logic that `json_decode(json_encode($arr), false)` uses.
 */
function arrayToObject(array $array, $maxDepth = 10) {
    if($maxDepth == 0) {
        return $array;
    }

    if(isArrayAssociative($array)) {
        $newObject = new \stdClass;
        foreach ($array as $key => $value) {
            if(is_array($value)) {
                $newObject->{$key} = arrayToObject($value, $maxDepth - 1);
            } else {
                $newObject->{$key} = $value;
            }
        }
        return $newObject;
    } else {

        $newArray = array();
        foreach ($array as $value) {
            if(is_array($value)) {
                $newArray[] = arrayToObject($value, $maxDepth - 1);
            } else {
                $newArray[] = $value;
            }                
        }
        return $newArray;
    }
}

2

Лучший метод в мире :)

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

если вы используете разные методы, у вас будут проблемы. Это лучший метод. Вы когда-либо видели.


2

Многомерные массивы в объект. этот код используется для преобразования метода try и catch API поиска Bing.

try {
        // Perform the Web request and get the JSON response
        $context = stream_context_create($options);
        $results = file_get_contents($url . "?cc=" . $country . "&category=" . $type, false, $context);
        $results = json_decode($results);
        return response()->json($results);
    } catch (\Exception $e) {
        $results = array('value' => array(
                (object) array(
                    "name" => "Unable to Retrive News",
                    "url" => "http://www.sample.com/",
                    "image" => (object) array("thumbnail" => (object) array("contentUrl" => "")),
                    "publishedAt" => "",
                    "description" => "")
            )
        );
        $results = (object) $results;
        return response()->json($results);
    }

2

Вы можете использовать Reflection:

<?php

$array = ['name'=>'maria','age'=>33];

class Person {

    public $name;
    public $age;

    public function __construct(string $name, string $age){
        $this->name  = $name;
        $this->age = $age;
    }
}

function arrayToObject(array $array, string $class_name){

    $r = new ReflectionClass($class_name);
    $object = $r->newInstanceWithoutConstructor();
    $list = $r->getProperties();
    foreach($list as $prop){
      $prop->setAccessible(true);
      if(isset($array[$prop->name]))
        $prop->setValue($object, $array[$prop->name]);
    } 

    return $object;

}

$pessoa1 = arrayToObject($array, 'Person');
var_dump($pessoa1);

1

CakePHP имеет рекурсивный класс Set :: map, который в основном отображает массив в объект. Возможно, вам придется изменить внешний вид массива, чтобы объект выглядел так, как вы этого хотите.

http://api.cakephp.org/view_source/set/#line-158

В худшем случае, вы можете получить несколько идей из этой функции.


1

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

   function convert_array_to_object($array){
      $obj= new stdClass();
      foreach ($array as $k=> $v) {
         if (is_array($v)){
            $v = convert_array_to_object($v);   
         }
         $obj->{strtolower($k)} = $v;
      }
      return $obj;
   }

И помните , что если массив имел цифровые клавиши , они все еще могут быть ссылки в полученном объекте с помощью {}(например: $obj->prop->{4}->prop)


1

Вдохновленный всеми этими кодами, я попытался создать улучшенную версию с поддержкой: определенного имени класса, метода конструктора избегания, шаблона 'beans' и строгого режима (задайте только существующие свойства):

    class Util {

static function arrayToObject($array, $class = 'stdClass', $strict = false) {
        if (!is_array($array)) {
            return $array;
        }

        //create an instance of an class without calling class's constructor
        $object = unserialize(
                sprintf(
                        'O:%d:"%s":0:{}', strlen($class), $class
                )
        );

        if (is_array($array) && count($array) > 0) {
            foreach ($array as $name => $value) {
                $name = strtolower(trim($name));
                if (!empty($name)) {

                    if(method_exists($object, 'set'.$name)){
                        $object->{'set'.$name}(Util::arrayToObject($value));
                    }else{
                        if(($strict)){

                            if(property_exists($class, $name)){

                                $object->$name = Util::arrayToObject($value); 

                            }

                        }else{
                            $object->$name = Util::arrayToObject($value); 
                        }

                    }

                }
            }
            return $object;
        } else {
            return FALSE;
        }
        }
}

1

Код

Эта функция работает так же, как и json_decode(json_encode($arr), false).

function arrayToObject(array $arr)
{
    $flat = array_keys($arr) === range(0, count($arr) - 1);
    $out = $flat ? [] : new \stdClass();

    foreach ($arr as $key => $value) {
        $temp = is_array($value) ? $this->arrayToObject($value) : $value;

        if ($flat) {
            $out[] = $temp;
        } else {
            $out->{$key} = $temp;
        }
    }

    return $out;
}

тестирование

Тест 1: Плоский массив

$arr = ["a", "b", "c"];
var_export(json_decode(json_encode($arr)));
var_export($this->arrayToObject($arr));

Вывод:

array(
    0 => 'a',
    1 => 'b',
    2 => 'c',
)
array(
    0 => 'a',
    1 => 'b',
    2 => 'c',
)

Тест 2: Массив объектов

$arr = [["a" => 1], ["a" => 1], ["a" => 1]];
var_export(json_decode(json_encode($arr)));
var_export($this->arrayToObject($arr));

Вывод:

array(
    0 => stdClass::__set_state(array('a' => 1,)),
    1 => stdClass::__set_state(array('a' => 1,)),
    2 => stdClass::__set_state(array('a' => 1,)),
)
array(
    0 => stdClass::__set_state(array('a' => 1,)),
    1 => stdClass::__set_state(array('a' => 1,)),
    2 => stdClass::__set_state(array('a' => 1,)),
)

Тест 3: Объект

$arr = ["a" => 1];
var_export(json_decode($arr));
var_export($this->arrayToObject($arr));

Вывод:

stdClass::__set_state(array('a' => 1,))
stdClass::__set_state(array('a' => 1,))

0

я сделал это довольно простым способом,

    $list_years         = array();
    $object             = new stdClass();

    $object->year_id   = 1 ;
    $object->year_name = 2001 ;
    $list_years[]       = $object;
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.