web-dev-qa-db-fra.com

Convertir PHP objet à tableau associatif

J'intègre une API sur mon site Web qui fonctionne avec des données stockées dans des objets pendant que mon code est écrit à l'aide de tableaux.

Je voudrais une fonction rapide et sale pour convertir un objet en un tableau.

625
Haroldo

Il suffit de le dicter

$array =  (array) $yourObject;

De http://www.php.net/manual/fr/language.types.array.php

Si un objet est converti en tableau, le résultat est un tableau dont les éléments sont les propriétés de l'objet. Les clés sont les noms des variables membres, à quelques exceptions près: les propriétés d'entier sont inaccessibles; Les variables privées ont le nom de la classe ajouté au nom de la variable; Les variables protégées ont un '*' ajouté au nom de la variable. Ces valeurs ajoutées au début ont des octets nuls de chaque côté.

Exemple: objet simple

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

var_dump( (array) $object );

Sortie:

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

Exemple: objet complexe

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 );

Sortie (avec\0s édités pour plus de clarté):

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

Sortie avec var_export au lieu de var_dump:

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

Le transtypage de cette manière ne fera pas une transposition en profondeur du graphe d'objet et vous devez appliquer les octets nuls (comme expliqué dans la citation manuelle) pour accéder aux attributs non publics. Cela fonctionne donc mieux lors du transtypage d'objets StdClass ou d'objets contenant uniquement des propriétés publiques. Pour rapide et sale (ce que vous avez demandé) c'est bien.

Voir également cet article de blog détaillé: 

1189
Gordon

Vous pouvez rapidement convertir des objets profondément imbriqués en tableaux associatifs en vous fiant au comportement des fonctions d'encodage/décodage JSON:

$array = json_decode(json_encode($nested_object), true);
281
Jeff Standen

Depuis le premier hit Google pour "objet php à tableau assoc", nous avons ceci:

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;
}

Source à codesnippets.joyent.com .

63
Maurycy

Si vos propriétés d'objet sont publiques, vous pouvez faire:

$array =  (array) $object;

S'ils sont privés ou protégés, ils auront des noms de clé étranges sur le tableau. Donc, dans ce cas, vous aurez besoin de la fonction suivante:

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;
}
51
ramonztro
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());

Sortie

array(2) {
    ["b"]=>
    string(3) "two"
    ["Testc"]=>
    int(1)
}
array(1) {
    ["b"]=>
    string(3) "two"
}
10
Isius

Toutes les autres réponses publiées ici ne fonctionnent qu'avec des attributs publics. Voici une solution qui fonctionne avec les objets de type javabean - utilisant la réflexion et les accesseurs:

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;
}
10
Francois Bourgeois

Voici du code:

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;
}
8
Khalid

Qu'en est-il de get_object_vars($obj)? Cela semble utile si vous souhaitez uniquement accéder aux propriétés publiques d'un objet http://www.php.net/function.get-object-vars

6
Joe

Tapez cast votre objet dans un tableau.

$arr =  (array) $Obj;

Cela résoudra votre problème.

5
Adeel

Pour convertir un objet en tableau, il suffit de le lancer explicitement

$name_of_array =  (array) $name_of_object;
5
Shrish Shrivastava

Salut,

Voici ma fonction récursive PHP pour convertir des objets PHP en un tableau associatif 

// --------------------------------------------------------- 
// ----- 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;
}


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

Exemple d'utilisation:

// ---- 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); 
4
rabatto

Vous pouvez également créer une fonction dans PHP pour convertir un tableau d'objets.

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

Vous pouvez facilement utiliser cette fonction pour obtenir un résultat.

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;
  }

utiliser> = php5

4
Fiacre AYEDOUN

Fonction personnalisée pour convertir stdClass en tableau:

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;
    }
}

Une autre fonction personnalisée pour convertir Array en 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;
    }
}

Exemple d'utilisation:

    // 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
Bishoy

Vous voudrez peut-être faire cela lorsque vous obtiendrez des données sous forme d'objets à partir de bases de données ->

// 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;
}
3
metaldog
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;
}

retourne un tableau sans caractères spéciaux ni noms de classe

3
ovnia

Tout d'abord, si vous avez besoin d'un tableau d'objet, vous devriez probablement constituer les données en tant que tableau en premier. Penses-y. 

N'utilisez pas l'instruction foreach ou les transformations JSON. Si vous planifiez cela, encore une fois, vous travaillez avec une structure de données, pas avec un objet.

Si vous en avez vraiment besoin, utilisez une approche orientée objet pour obtenir un code propre et maintenable. Par exemple:

Objet sous forme de tableau

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

Si vous avez besoin de toutes les propriétés, utilisez l'objet transfer

class PersonTransferObject
{
    private $person;

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

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

 }
3
John Smith

Conversion et suppression des étoiles agaçantes:

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

Ce sera probablement moins cher que d'utiliser des réflexions.

2
Fedir RYKHTIK

Vous pouvez aussi utiliser Le composant 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
Andrey Nilov

Quelques améliorations au code "bien connu"

/*** 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

Notez que si la fonction est membre d'une classe (comme ci-dessus), vous devez changer __FUNCTION__ en __METHOD__

1
Gilbert BENABOU

Solution courte de @ 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
Bsienn

Cette réponse n'est que l'union des différentes réponses de cet article, mais c'est la solution pour convertir un objet PHP avec des propriétés publiques ou privées avec des valeurs simples ou des tableaux dans un tableau associatif ...

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;
}
1
Daniel Guerrero

Pour votre cas, il était juste/beau d'utiliser les modèles "décorateur" ou "modèle de date" Par exemple:

Votre modèle

class Car {
    /** @var int */
    private $color;

    /** @var string */
    private $model;

    /** @var string */
    private $type;

    /**
     * @return int
     */
    public function getColor(): int
    {
        return $this->color;
    }

    /**
     * @param int $color
     * @return Car
     */
    public function setColor(int $color): Car
    {
        $this->color = $color;
        return $this;
    }

    /**
     * @return string
     */
    public function getModel(): string
    {
        return $this->model;
    }

    /**
     * @param string $model
     * @return Car
     */
    public function setModel(string $model): Car
    {
        $this->model = $model;

        return $this;
    }

    /**
     * @return string
     */
    public function getType(): string
    {
        return $this->type;
    }

    /**
     * @param string $type
     * @return Car
     */
    public function setType(string $type): Car
    {
        $this->type = $type;

        return $this;
    }
}

Décorateur

class CarArrayDecorator
{
    /** @var Car */
    private $car;

    /**
     * CarArrayDecorator constructor.
     * @param Car $car
     */
    public function __construct(Car $car)
    {
        $this->car = $car;
    }

    /**
     * @return array
     */
    public function getArray(): array
    {
        return [
            'color' => $this->car->getColor(),
            'type' => $this->car->getType(),
            'model' => $this->car->getModel(),
        ];
    }
}

Usage

$car = new Car();
$car->setType('type#');
$car->setModel('model#1');
$car->setColor(255);

$carDecorator = new CarArrayDecorator($car);
$carResponseData = $carDecorator->getArray();

Ce sera donc un code plus beau et plus correct.

0
Daniel Abyan

Je pense que c'est une bonne idée d'utiliser trait pour stocker la logique de conversion objet à tableau. Exemple simple

trait ArrayAwareTrait
{
    /**
     * Return list of Entity's parameters
     * @return array
     */
    public function toArray()
    {
        $props = array_flip($this->getPropertiesList());
        return array_map(
            function ($item) {
                if ($item instanceof \DateTime) {
                    return $item->format(DATE_ATOM);
                }
                return $item;
            },
            array_filter(get_object_vars($this), function ($key) use ($props) {
                return array_key_exists($key, $props);
            }, ARRAY_FILTER_USE_KEY)
        );
    }



    /**
     * @return array
     */
    protected function getPropertiesList()
    {
        if (method_exists($this, '__sleep')) {
            return $this->__sleep();
        }
        if (defined('static::PROPERTIES')) {
            return static::PROPERTIES;
        }
        return [];
    }
}

class OrderResponse
{
    use ArrayAwareTrait;

    const PROP_ORDER_ID = 'orderId';
    const PROP_TITLE = 'title';
    const PROP_QUANTITY = 'quantity';
    const PROP_BUYER_USERNAME = 'buyerUsername';
    const PROP_COST_VALUE = 'costValue';
    const PROP_ADDRESS = 'address';

    private $orderId;
    private $title;
    private $quantity;
    private $buyerUsername;
    private $costValue;
    private $address;

    /**
     * @param $orderId
     * @param $title
     * @param $quantity
     * @param $buyerUsername
     * @param $costValue
     * @param $address
     */
    public function __construct(
        $orderId,
        $title,
        $quantity,
        $buyerUsername,
        $costValue,
        $address
    ) {
        $this->orderId = $orderId;
        $this->title = $title;
        $this->quantity = $quantity;
        $this->buyerUsername = $buyerUsername;
        $this->costValue = $costValue;
        $this->address = $address;
    }

    /**
     * @inheritDoc
     */
    public function __sleep()
    {
        return [
            static::PROP_ORDER_ID,
            static::PROP_TITLE,
            static::PROP_QUANTITY,
            static::PROP_BUYER_USERNAME,
            static::PROP_COST_VALUE,
            static::PROP_ADDRESS,
        ];
    }

    /**
     * @return mixed
     */
    public function getOrderId()
    {
        return $this->orderId;
    }

    /**
     * @return mixed
     */
    public function getTitle()
    {
        return $this->title;
    }

    /**
     * @return mixed
     */
    public function getQuantity()
    {
        return $this->quantity;
    }

    /**
     * @return mixed
     */
    public function getBuyerUsername()
    {
        return $this->buyerUsername;
    }

    /**
     * @return mixed
     */
    public function getCostValue()
    {
        return $this->costValue;
    }

    /**
     * @return string
     */
    public function getAddress()
    {
        return $this->address;
    }
}

$orderResponse = new OrderResponse(...);
var_dump($orderResponse->toArray());
0
Vitaly Pugach

Comme beaucoup de gens trouvent ce fil à cause de problèmes avec l'accès dynamique aux attributs d'un objet, je vous ferai remarquer que vous pouvez le faire en php: $valueRow->{"valueName"}

En contexte (sortie HTML supprimée pour plus de lisibilité):

$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 .= " ";
        }

    }

}

Ici, j'ai créé une méthode objectToArray () , qui fonctionne également avec les objets récursifs, comme lorsque $objectA contient $objectB qui pointe à nouveau vers $objectA.

De plus, j'ai limité la sortie aux propriétés publiques à l'aide de ReflectionClass. Débarrassez-vous de vous, si vous n'en avez pas besoin.

    /**
     * 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;
    }

Pour identifier les objets déjà utilisés, j'utilise une propriété protégée dans cette classe (abstraite), nommée $this->usedObjects. Si un objet imbriqué récursif est trouvé, il sera remplacé par la chaîne **recursive**. Sinon, il échouerait à cause d'une boucle infinie.

0
Armin

Voici ma proposition, si vous avez des objets dans des objets ayant même des membres privés:

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
Karol Gasienica

En utilisant la conversion de type, vous pouvez résoudre votre problème . Ajoutez simplement les lignes suivantes à votre objet de retour:

$arrObj = array(yourReturnedObject);

vous pouvez également ajouter une nouvelle paire clé/valeur en utilisant:

$arrObj['key'] = value;
0
Naveen Gupta
$Menu = new Admin_Model_DbTable_Menu(); 
$row = $Menu->fetchRow($Menu->select()->where('id = ?', $id));
$Addmenu = new Admin_Form_Addmenu(); 
$Addmenu->populate($row->toArray());