Related
I'm integrating an API to my website which works with data stored in objects while my code is written using arrays.
I'd like a quick-and-dirty function to convert an object to an array.
Just typecast it
$array = (array) $yourObject;
From Arrays:
If an object is converted to an array, the result is an array whose elements are the object's properties. The keys are the member variable names, with a few notable exceptions: integer properties are unaccessible; private variables have the class name prepended to the variable name; protected variables have a '*' prepended to the variable name. These prepended values have null bytes on either side.
Example: Simple Object
$object = new StdClass;
$object->foo = 1;
$object->bar = 2;
var_dump( (array) $object );
Output:
array(2) {
'foo' => int(1)
'bar' => int(2)
}
Example: Complex Object
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 );
Output (with \0s edited in for clarity):
array(3) {
'\0Foo\0foo' => int(1)
'\0*\0bar' => int(2)
'baz' => class stdClass#2 (0) {}
}
Output with var_export instead of var_dump:
array (
'' . "\0" . 'Foo' . "\0" . 'foo' => 1,
'' . "\0" . '*' . "\0" . 'bar' => 2,
'baz' =>
stdClass::__set_state(array(
)),
)
Typecasting this way will not do deep casting of the object graph and you need to apply the null bytes (as explained in the manual quote) to access any non-public attributes. So this works best when casting StdClass objects or objects with only public properties. For quick and dirty (what you asked for) it's fine.
Also see this in-depth blog post:
Fast PHP Object to Array conversion
You can quickly convert deeply nested objects to associative arrays by relying on the behavior of the JSON encode/decode functions:
$array = json_decode(json_encode($nested_object), true);
From the first Google hit for "PHP object to assoc array" we have this:
function object_to_array($data)
{
if (is_array($data) || is_object($data))
{
$result = [];
foreach ($data as $key => $value)
{
$result[$key] = (is_array($value) || is_object($value)) ? object_to_array($value) : $value;
}
return $result;
}
return $data;
}
The source is at codesnippets.joyent.com.
To compare it to the solution of json_decode & json_encode, this one seems faster. Here is a random benchmark (using the simple time measuring):
$obj = (object) [
'name' =>'Mike',
'surname' =>'Jovanson',
'age' =>'45',
'time' =>1234567890,
'country' =>'Germany',
];
##### 100 000 cycles ######
* json_decode(json_encode($var)) : 4.15 sec
* object_to_array($var) : 0.93 sec
If your object properties are public you can do:
$array = (array) $object;
If they are private or protected, they will have weird key names on the array. So, in this case you will need the following function:
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;
}
What about get_object_vars($obj)? It seems useful if you only want to access the public properties of an object.
See get_object_vars.
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());
Output
array(2) {
["b"]=>
string(3) "two"
["Testc"]=>
int(1)
}
array(1) {
["b"]=>
string(3) "two"
}
Type cast your object to an array.
$arr = (array) $Obj;
It will solve your problem.
Here is some 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;
}
All other answers posted here are only working with public attributes. Here is one solution that works with JavaBeans-like objects using reflection and getters:
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;
}
To convert an object into array just cast it explicitly:
$name_of_array = (array) $name_of_object;
You can also create a function in PHP to convert an object array:
function object_to_array($object) {
return (array) $object;
}
Use:
function readObject($object) {
$name = get_class ($object);
$name = str_replace('\\', "\\\\", $name); // Outcomment this line, if you don't 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;
}
It returns an array without special characters and class names.
You can easily use this function to get the result:
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;
}
Use PHP 5 or later.
Short solution of #SpYk3HH
function objectToArray($o)
{
$a = array();
foreach ($o as $k => $v)
$a[$k] = (is_array($v) || is_object($v)) ? objectToArray($v): $v;
return $a;
}
Here is my recursive PHP function to convert PHP objects to an associative array:
// ---------------------------------------------------------
// ----- object_to_array_recursive --- 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_recursive($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_recursive($val);
}
else {
$res_arr[$akey] = (empty($val)) ? $empty : (string)$val;
}
$i++;
}
}
return $res_arr;
}
// ---------------------------------------------------------
// ---------------------------------------------------------
Usage example:
// ---- Return associative array from object, ... use:
$new_arr1 = object_to_array_recursive($my_object);
// -- or --
// $new_arr1 = object_to_array_recursive($my_object, TRUE);
// -- or --
// $new_arr1 = object_to_array_recursive($my_object, 1);
// ---- Return numeric array from object, ... use:
$new_arr2 = object_to_array_recursive($my_object, FALSE);
Custom function to convert stdClass to an array:
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;
}
}
Another custom function to convert Array to 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;
}
}
Usage Example:
// 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);
First of all, if you need an array from an object you probably should constitute the data as an array first. Think about it.
Don't use a foreach statement or JSON transformations. If you're planning this, again you're working with a data structure, not with an object.
If you really need it use an object-oriented approach to have a clean and maintainable code. For example:
Object as array
class PersonArray implements \ArrayAccess, \IteratorAggregate
{
public function __construct(Person $person) {
$this->person = $person;
}
// ...
}
If you need all properties, use a transfer object:
class PersonTransferObject
{
private $person;
public function __construct(Person $person) {
$this->person = $person;
}
public function toArray() {
return [
// 'name' => $this->person->getName();
];
}
}
Also you can use The Symfony Serializer Component
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);
You might want to do this when you obtain data as objects from databases:
// 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;
}
This answer is only the union of the different answers of this post, but it's the solution to convert a PHP object with public or private properties with simple values or arrays to an associative array...
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;
}
Some impovements to the "well-knwon" code
/*** 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
Notice that if the function is member of a class (like above) you must change __FUNCTION__ to __METHOD__
For your case it was right/beautiful if you would use the "decorator" or "date model transformation" patterns. For example:
Your model
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;
}
}
Decorator
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();
So it will be more beautiful and more correct code.
Converting and removing annoying stars:
$array = (array) $object;
foreach($array as $key => $val)
{
$new_array[str_replace('*_', '', $key)] = $val;
}
Probably, it will be cheaper than using reflections.
I use this (needed recursive solution with proper keys):
/**
* This method returns the array corresponding to an object, including non public members.
*
* If the deep flag is true, is will operate recursively, otherwise (if false) just at the first level.
*
* #param object $obj
* #param bool $deep = true
* #return array
* #throws \Exception
*/
public static function objectToArray(object $obj, bool $deep = true)
{
$reflectionClass = new \ReflectionClass(get_class($obj));
$array = [];
foreach ($reflectionClass->getProperties() as $property) {
$property->setAccessible(true);
$val = $property->getValue($obj);
if (true === $deep && is_object($val)) {
$val = self::objectToArray($val);
}
$array[$property->getName()] = $val;
$property->setAccessible(false);
}
return $array;
}
Example of usage, the following code:
class AA{
public $bb = null;
protected $one = 11;
}
class BB{
protected $two = 22;
}
$a = new AA();
$b = new BB();
$a->bb = $b;
var_dump($a)
Will print this:
array(2) {
["bb"] => array(1) {
["two"] => int(22)
}
["one"] => int(11)
}
There's my proposal, if you have objects in objects with even private members:
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;
}
Since a lot of people find this question because of having trouble with dynamically access attributes of an object, I will just point out that you can do this in PHP: $valueRow->{"valueName"}
In context (removed HTML output for readability):
$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 .= " ";
}
}
}
I think it is a nice idea to use traits to store object-to-array converting logic. A simple example:
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());
$Menu = new Admin_Model_DbTable_Menu();
$row = $Menu->fetchRow($Menu->select()->where('id = ?', $id));
$Addmenu = new Admin_Form_Addmenu();
$Addmenu->populate($row->toArray());
Here I've made an objectToArray() method, which also works with recursive objects, like when $objectA contains $objectB which points again to $objectA.
Additionally I've restricted the output to public properties using ReflectionClass. Get rid of it, if you don't need it.
/**
* 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;
}
To identify already used objects, I am using a protected property in this (abstract) class, named $this->usedObjects. If a recursive nested object is found, it will be replaced by the string **recursive**. Otherwise it would fail in because of infinite loop.
By using typecasting you can resolve your problem.
Just add the following lines to your return object:
$arrObj = array(yourReturnedObject);
You can also add a new key and value pair to it by using:
$arrObj['key'] = value;
I can read custom annotations in Symfony with class Doctrine\Common\Annotations\AnnotationReader.
It looks like below. I have described property:
/**
* #var array
* #MappingClient(ignore=true)
*/
protected static $myProperty = [];
And I may parse annotation #MappingClient:
$class = new \ReflectionClass(get_called_class());
$property = $class->getProperty('myProperty');
$annotationReader = new AnnotationReader();
$mappingClient = $annotationReader
->getPropertyAnnotation($property, 'MyClass\Annotation\MappingClient');
And also I need to parse type of property, what described in #var array. I understand what I can parse it with regex on $property->getDocComment(). But how may I do it just with Symfony classes if getPropertyAnnotation() ignoring #var and other standard declarations? Is there a more elegant way of?
If you use Symfony 2.8 or Symfony 3 you can use the PropertyInfo component. It does exactly that.
In a controller:
$this->get('property_info')->getTypes('FooClass', 'foo'); // Must be enabled in the framework configuration
// array(1) {
// [0] =>
// class Symfony\Component\PropertyInfo\Type#36 (6) {
// private $builtinType => string(6) "object"
// private $nullable => bool(false)
// private $class => string(8) "DateTime"
// private $collection => bool(false)
// private $collectionKeyType => NULL
// private $collectionValueType => NULL
// }
// }
I solved this with extension on AnnotationReader:
namespace MyPath\Annotation;
use Doctrine\Common\Annotations\AnnotationReader;
class UniversalAnnotationReader extends AnnotationReader
{
/**
* Get type of property from property declaration
*
* #param \ReflectionProperty $property
*
* #return null|string
*/
public function getPropertyType(\ReflectionProperty $property)
{
$doc = $property->getDocComment();
preg_match_all('##(.*?)\n#s', $doc, $annotations);
if (isset($annotations[1])) {
foreach ($annotations[1] as $annotation) {
preg_match_all('#\s*(.*?)\s+#s', $annotation, $parts);
if (!isset($parts[1])) {
continue;
}
$declaration = $parts[1];
if (isset($declaration[0]) && $declaration[0] === 'var') {
if (isset($declaration[1])) {
if (substr($declaration[1], 0, 1) === '$') {
return null;
}
else {
return $declaration[1];
}
}
}
}
return null;
}
return $doc;
}
}
And how I use this:
$annotationReader = new UniversalAnnotationReader();
$class = new \ReflectionClass(get_called_class());
$type = $annotationReader->getPropertyType($class->getProperty('myProperty'));
Im a fan of the jackson mapper in Java, and I'm a bit lost without it in php. I would like an equivalent.
So far the closest I have come across is this, however, it requires the fields to be declared as public, and I dont want to do that:
https://github.com/netresearch/jsonmapper
I want something that does everything that that does, with this sort of code:
<?php
class Contact
{
/**
* Full name
* #var string
*/
public $name; //<- I want this to be private
/**
* #var Address //<- and this
*/
public $address;
}
class Address
{
public $street;<- and this
public $city;<- and this
public function getGeoCoords()
{
//do something with the $street and $city
}
}
$json = json_decode(file_get_contents('http://example.org/bigbang.json'));
$mapper = new JsonMapper();
$contact = $mapper->map($json, new Contact());
Json from file_get_contents:
{
'name':'Sheldon Cooper',
'address': {
'street': '2311 N. Los Robles Avenue',
'city': 'Pasadena'
}
}
So I dont want to be writing individual constructors, or anything individual at all.
Im sure there would be something that does this out of the box using reflection?
You can provide a setter method for protected and private variables:
public function setName($name)
{
$this->name = $name;
}
JsonMapper will automatically use it.
Since version 1.1.0 JsonMapper supports mapping private and protected properties.
This can be achieved very easily and nicely using Closures.
There is even no need to create setter functions.
<?php
class A {
private $b;
public $c;
function d() {
}
}
$data = [
'b' => 'b-value',
'c' => 'c-value',
'd' => 'function',
];
class JsonMapper {
public function map( $data, $context ) {
$json_mapper = function() use ( $data ) {
foreach ($data as $key => $value) {
if ( property_exists( $this, $key ) ) {
$this->{$key} = $value;
}
}
};
$json_mapper = $json_mapper->bindTo( $context, $context );
$json_mapper();
return $context;
}
}
$mapper = new JsonMapper();
$a = $mapper->map( $data, new A );
print_r($a);
Sorry, I don't have enough 'reputation' so can't add a comment.
I've only been using Java for a few month, but my understanding is that your classes in Java will all have getters and settings, which is how Jackson is able to set the value of a private property.
To do the same in PHP, I suspect you would need to make your properties private, and create getter and setter methods...
public function setName($name) {
$this->name = name;
}
Then within your Mapper, use reflection to call the setter.
The way I would do this would be to look at the keys you have in the JSON, and try to put together a method name.
For example, if there's a key in the JSON labelled 'name'...
$className = "Contact";
$object = json_decode($jsonResponse);
$classObject = new $className();
foreach ($object as $key => $value) {
$methodName = "set" . ucfirst($key);
if (method_exists($classObject, $methodName)) {
$classObject->$methodName($value);
}
}
The above may not be exactly right, but I hope it gives you an idea.
To expand on the above, I've put together the following example which seems to do what you require?
class Contact {
private $name;
private $telephone;
public function setName($name) {
$this->name = $name;
}
public function setTelephone($telephone) {
$this->telephone = $telephone;
}
public function getName() {
return $this->name;
}
public function getTelephone() {
return $this->telephone;
}
}
class Mapper {
private $jsonObject;
public function map($jsonString, $object) {
$this->jsonObject = json_decode($jsonString);
if (count($this->jsonObject) > 0) {
foreach ($this->jsonObject as $key => $value) {
$methodName = "set" . ucfirst($key);
if (method_exists($object, $methodName)) {
$object->$methodName($value);
}
}
}
return $object;
}
}
$myContact = new stdClass();
$myContact->name = "John Doe";
$myContact->telephone = "0123 123 1234";
$jsonString = json_encode($myContact);
$mapper = new Mapper();
$contact = $mapper->map($jsonString, new Contact());
echo "Name: " . $contact->getName() . "<br>";
echo "Telephone: " . $contact->getTelephone();
I'm integrating an API to my website which works with data stored in objects while my code is written using arrays.
I'd like a quick-and-dirty function to convert an object to an array.
Just typecast it
$array = (array) $yourObject;
From Arrays:
If an object is converted to an array, the result is an array whose elements are the object's properties. The keys are the member variable names, with a few notable exceptions: integer properties are unaccessible; private variables have the class name prepended to the variable name; protected variables have a '*' prepended to the variable name. These prepended values have null bytes on either side.
Example: Simple Object
$object = new StdClass;
$object->foo = 1;
$object->bar = 2;
var_dump( (array) $object );
Output:
array(2) {
'foo' => int(1)
'bar' => int(2)
}
Example: Complex Object
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 );
Output (with \0s edited in for clarity):
array(3) {
'\0Foo\0foo' => int(1)
'\0*\0bar' => int(2)
'baz' => class stdClass#2 (0) {}
}
Output with var_export instead of var_dump:
array (
'' . "\0" . 'Foo' . "\0" . 'foo' => 1,
'' . "\0" . '*' . "\0" . 'bar' => 2,
'baz' =>
stdClass::__set_state(array(
)),
)
Typecasting this way will not do deep casting of the object graph and you need to apply the null bytes (as explained in the manual quote) to access any non-public attributes. So this works best when casting StdClass objects or objects with only public properties. For quick and dirty (what you asked for) it's fine.
Also see this in-depth blog post:
Fast PHP Object to Array conversion
You can quickly convert deeply nested objects to associative arrays by relying on the behavior of the JSON encode/decode functions:
$array = json_decode(json_encode($nested_object), true);
From the first Google hit for "PHP object to assoc array" we have this:
function object_to_array($data)
{
if (is_array($data) || is_object($data))
{
$result = [];
foreach ($data as $key => $value)
{
$result[$key] = (is_array($value) || is_object($value)) ? object_to_array($value) : $value;
}
return $result;
}
return $data;
}
The source is at codesnippets.joyent.com.
To compare it to the solution of json_decode & json_encode, this one seems faster. Here is a random benchmark (using the simple time measuring):
$obj = (object) [
'name' =>'Mike',
'surname' =>'Jovanson',
'age' =>'45',
'time' =>1234567890,
'country' =>'Germany',
];
##### 100 000 cycles ######
* json_decode(json_encode($var)) : 4.15 sec
* object_to_array($var) : 0.93 sec
If your object properties are public you can do:
$array = (array) $object;
If they are private or protected, they will have weird key names on the array. So, in this case you will need the following function:
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;
}
What about get_object_vars($obj)? It seems useful if you only want to access the public properties of an object.
See get_object_vars.
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());
Output
array(2) {
["b"]=>
string(3) "two"
["Testc"]=>
int(1)
}
array(1) {
["b"]=>
string(3) "two"
}
Type cast your object to an array.
$arr = (array) $Obj;
It will solve your problem.
Here is some 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;
}
All other answers posted here are only working with public attributes. Here is one solution that works with JavaBeans-like objects using reflection and getters:
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;
}
To convert an object into array just cast it explicitly:
$name_of_array = (array) $name_of_object;
You can also create a function in PHP to convert an object array:
function object_to_array($object) {
return (array) $object;
}
Use:
function readObject($object) {
$name = get_class ($object);
$name = str_replace('\\', "\\\\", $name); // Outcomment this line, if you don't 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;
}
It returns an array without special characters and class names.
You can easily use this function to get the result:
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;
}
Use PHP 5 or later.
Short solution of #SpYk3HH
function objectToArray($o)
{
$a = array();
foreach ($o as $k => $v)
$a[$k] = (is_array($v) || is_object($v)) ? objectToArray($v): $v;
return $a;
}
Here is my recursive PHP function to convert PHP objects to an associative array:
// ---------------------------------------------------------
// ----- object_to_array_recursive --- 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_recursive($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_recursive($val);
}
else {
$res_arr[$akey] = (empty($val)) ? $empty : (string)$val;
}
$i++;
}
}
return $res_arr;
}
// ---------------------------------------------------------
// ---------------------------------------------------------
Usage example:
// ---- Return associative array from object, ... use:
$new_arr1 = object_to_array_recursive($my_object);
// -- or --
// $new_arr1 = object_to_array_recursive($my_object, TRUE);
// -- or --
// $new_arr1 = object_to_array_recursive($my_object, 1);
// ---- Return numeric array from object, ... use:
$new_arr2 = object_to_array_recursive($my_object, FALSE);
Custom function to convert stdClass to an array:
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;
}
}
Another custom function to convert Array to 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;
}
}
Usage Example:
// 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);
First of all, if you need an array from an object you probably should constitute the data as an array first. Think about it.
Don't use a foreach statement or JSON transformations. If you're planning this, again you're working with a data structure, not with an object.
If you really need it use an object-oriented approach to have a clean and maintainable code. For example:
Object as array
class PersonArray implements \ArrayAccess, \IteratorAggregate
{
public function __construct(Person $person) {
$this->person = $person;
}
// ...
}
If you need all properties, use a transfer object:
class PersonTransferObject
{
private $person;
public function __construct(Person $person) {
$this->person = $person;
}
public function toArray() {
return [
// 'name' => $this->person->getName();
];
}
}
Also you can use The Symfony Serializer Component
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);
You might want to do this when you obtain data as objects from databases:
// 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;
}
This answer is only the union of the different answers of this post, but it's the solution to convert a PHP object with public or private properties with simple values or arrays to an associative array...
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;
}
Some impovements to the "well-knwon" code
/*** 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
Notice that if the function is member of a class (like above) you must change __FUNCTION__ to __METHOD__
For your case it was right/beautiful if you would use the "decorator" or "date model transformation" patterns. For example:
Your model
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;
}
}
Decorator
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();
So it will be more beautiful and more correct code.
Converting and removing annoying stars:
$array = (array) $object;
foreach($array as $key => $val)
{
$new_array[str_replace('*_', '', $key)] = $val;
}
Probably, it will be cheaper than using reflections.
I use this (needed recursive solution with proper keys):
/**
* This method returns the array corresponding to an object, including non public members.
*
* If the deep flag is true, is will operate recursively, otherwise (if false) just at the first level.
*
* #param object $obj
* #param bool $deep = true
* #return array
* #throws \Exception
*/
public static function objectToArray(object $obj, bool $deep = true)
{
$reflectionClass = new \ReflectionClass(get_class($obj));
$array = [];
foreach ($reflectionClass->getProperties() as $property) {
$property->setAccessible(true);
$val = $property->getValue($obj);
if (true === $deep && is_object($val)) {
$val = self::objectToArray($val);
}
$array[$property->getName()] = $val;
$property->setAccessible(false);
}
return $array;
}
Example of usage, the following code:
class AA{
public $bb = null;
protected $one = 11;
}
class BB{
protected $two = 22;
}
$a = new AA();
$b = new BB();
$a->bb = $b;
var_dump($a)
Will print this:
array(2) {
["bb"] => array(1) {
["two"] => int(22)
}
["one"] => int(11)
}
There's my proposal, if you have objects in objects with even private members:
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;
}
Since a lot of people find this question because of having trouble with dynamically access attributes of an object, I will just point out that you can do this in PHP: $valueRow->{"valueName"}
In context (removed HTML output for readability):
$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 .= " ";
}
}
}
I think it is a nice idea to use traits to store object-to-array converting logic. A simple example:
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());
$Menu = new Admin_Model_DbTable_Menu();
$row = $Menu->fetchRow($Menu->select()->where('id = ?', $id));
$Addmenu = new Admin_Form_Addmenu();
$Addmenu->populate($row->toArray());
Here I've made an objectToArray() method, which also works with recursive objects, like when $objectA contains $objectB which points again to $objectA.
Additionally I've restricted the output to public properties using ReflectionClass. Get rid of it, if you don't need it.
/**
* 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;
}
To identify already used objects, I am using a protected property in this (abstract) class, named $this->usedObjects. If a recursive nested object is found, it will be replaced by the string **recursive**. Otherwise it would fail in because of infinite loop.
By using typecasting you can resolve your problem.
Just add the following lines to your return object:
$arrObj = array(yourReturnedObject);
You can also add a new key and value pair to it by using:
$arrObj['key'] = value;
I'm integrating an API to my website which works with data stored in objects while my code is written using arrays.
I'd like a quick-and-dirty function to convert an object to an array.
Just typecast it
$array = (array) $yourObject;
From Arrays:
If an object is converted to an array, the result is an array whose elements are the object's properties. The keys are the member variable names, with a few notable exceptions: integer properties are unaccessible; private variables have the class name prepended to the variable name; protected variables have a '*' prepended to the variable name. These prepended values have null bytes on either side.
Example: Simple Object
$object = new StdClass;
$object->foo = 1;
$object->bar = 2;
var_dump( (array) $object );
Output:
array(2) {
'foo' => int(1)
'bar' => int(2)
}
Example: Complex Object
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 );
Output (with \0s edited in for clarity):
array(3) {
'\0Foo\0foo' => int(1)
'\0*\0bar' => int(2)
'baz' => class stdClass#2 (0) {}
}
Output with var_export instead of var_dump:
array (
'' . "\0" . 'Foo' . "\0" . 'foo' => 1,
'' . "\0" . '*' . "\0" . 'bar' => 2,
'baz' =>
stdClass::__set_state(array(
)),
)
Typecasting this way will not do deep casting of the object graph and you need to apply the null bytes (as explained in the manual quote) to access any non-public attributes. So this works best when casting StdClass objects or objects with only public properties. For quick and dirty (what you asked for) it's fine.
Also see this in-depth blog post:
Fast PHP Object to Array conversion
You can quickly convert deeply nested objects to associative arrays by relying on the behavior of the JSON encode/decode functions:
$array = json_decode(json_encode($nested_object), true);
From the first Google hit for "PHP object to assoc array" we have this:
function object_to_array($data)
{
if (is_array($data) || is_object($data))
{
$result = [];
foreach ($data as $key => $value)
{
$result[$key] = (is_array($value) || is_object($value)) ? object_to_array($value) : $value;
}
return $result;
}
return $data;
}
The source is at codesnippets.joyent.com.
To compare it to the solution of json_decode & json_encode, this one seems faster. Here is a random benchmark (using the simple time measuring):
$obj = (object) [
'name' =>'Mike',
'surname' =>'Jovanson',
'age' =>'45',
'time' =>1234567890,
'country' =>'Germany',
];
##### 100 000 cycles ######
* json_decode(json_encode($var)) : 4.15 sec
* object_to_array($var) : 0.93 sec
If your object properties are public you can do:
$array = (array) $object;
If they are private or protected, they will have weird key names on the array. So, in this case you will need the following function:
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;
}
What about get_object_vars($obj)? It seems useful if you only want to access the public properties of an object.
See get_object_vars.
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());
Output
array(2) {
["b"]=>
string(3) "two"
["Testc"]=>
int(1)
}
array(1) {
["b"]=>
string(3) "two"
}
Type cast your object to an array.
$arr = (array) $Obj;
It will solve your problem.
Here is some 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;
}
All other answers posted here are only working with public attributes. Here is one solution that works with JavaBeans-like objects using reflection and getters:
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;
}
To convert an object into array just cast it explicitly:
$name_of_array = (array) $name_of_object;
You can also create a function in PHP to convert an object array:
function object_to_array($object) {
return (array) $object;
}
Use:
function readObject($object) {
$name = get_class ($object);
$name = str_replace('\\', "\\\\", $name); // Outcomment this line, if you don't 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;
}
It returns an array without special characters and class names.
You can easily use this function to get the result:
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;
}
Use PHP 5 or later.
Short solution of #SpYk3HH
function objectToArray($o)
{
$a = array();
foreach ($o as $k => $v)
$a[$k] = (is_array($v) || is_object($v)) ? objectToArray($v): $v;
return $a;
}
Here is my recursive PHP function to convert PHP objects to an associative array:
// ---------------------------------------------------------
// ----- object_to_array_recursive --- 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_recursive($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_recursive($val);
}
else {
$res_arr[$akey] = (empty($val)) ? $empty : (string)$val;
}
$i++;
}
}
return $res_arr;
}
// ---------------------------------------------------------
// ---------------------------------------------------------
Usage example:
// ---- Return associative array from object, ... use:
$new_arr1 = object_to_array_recursive($my_object);
// -- or --
// $new_arr1 = object_to_array_recursive($my_object, TRUE);
// -- or --
// $new_arr1 = object_to_array_recursive($my_object, 1);
// ---- Return numeric array from object, ... use:
$new_arr2 = object_to_array_recursive($my_object, FALSE);
Custom function to convert stdClass to an array:
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;
}
}
Another custom function to convert Array to 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;
}
}
Usage Example:
// 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);
First of all, if you need an array from an object you probably should constitute the data as an array first. Think about it.
Don't use a foreach statement or JSON transformations. If you're planning this, again you're working with a data structure, not with an object.
If you really need it use an object-oriented approach to have a clean and maintainable code. For example:
Object as array
class PersonArray implements \ArrayAccess, \IteratorAggregate
{
public function __construct(Person $person) {
$this->person = $person;
}
// ...
}
If you need all properties, use a transfer object:
class PersonTransferObject
{
private $person;
public function __construct(Person $person) {
$this->person = $person;
}
public function toArray() {
return [
// 'name' => $this->person->getName();
];
}
}
Also you can use The Symfony Serializer Component
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);
You might want to do this when you obtain data as objects from databases:
// 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;
}
This answer is only the union of the different answers of this post, but it's the solution to convert a PHP object with public or private properties with simple values or arrays to an associative array...
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;
}
Some impovements to the "well-knwon" code
/*** 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
Notice that if the function is member of a class (like above) you must change __FUNCTION__ to __METHOD__
For your case it was right/beautiful if you would use the "decorator" or "date model transformation" patterns. For example:
Your model
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;
}
}
Decorator
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();
So it will be more beautiful and more correct code.
Converting and removing annoying stars:
$array = (array) $object;
foreach($array as $key => $val)
{
$new_array[str_replace('*_', '', $key)] = $val;
}
Probably, it will be cheaper than using reflections.
I use this (needed recursive solution with proper keys):
/**
* This method returns the array corresponding to an object, including non public members.
*
* If the deep flag is true, is will operate recursively, otherwise (if false) just at the first level.
*
* #param object $obj
* #param bool $deep = true
* #return array
* #throws \Exception
*/
public static function objectToArray(object $obj, bool $deep = true)
{
$reflectionClass = new \ReflectionClass(get_class($obj));
$array = [];
foreach ($reflectionClass->getProperties() as $property) {
$property->setAccessible(true);
$val = $property->getValue($obj);
if (true === $deep && is_object($val)) {
$val = self::objectToArray($val);
}
$array[$property->getName()] = $val;
$property->setAccessible(false);
}
return $array;
}
Example of usage, the following code:
class AA{
public $bb = null;
protected $one = 11;
}
class BB{
protected $two = 22;
}
$a = new AA();
$b = new BB();
$a->bb = $b;
var_dump($a)
Will print this:
array(2) {
["bb"] => array(1) {
["two"] => int(22)
}
["one"] => int(11)
}
There's my proposal, if you have objects in objects with even private members:
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;
}
Since a lot of people find this question because of having trouble with dynamically access attributes of an object, I will just point out that you can do this in PHP: $valueRow->{"valueName"}
In context (removed HTML output for readability):
$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 .= " ";
}
}
}
I think it is a nice idea to use traits to store object-to-array converting logic. A simple example:
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());
$Menu = new Admin_Model_DbTable_Menu();
$row = $Menu->fetchRow($Menu->select()->where('id = ?', $id));
$Addmenu = new Admin_Form_Addmenu();
$Addmenu->populate($row->toArray());
Here I've made an objectToArray() method, which also works with recursive objects, like when $objectA contains $objectB which points again to $objectA.
Additionally I've restricted the output to public properties using ReflectionClass. Get rid of it, if you don't need it.
/**
* 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;
}
To identify already used objects, I am using a protected property in this (abstract) class, named $this->usedObjects. If a recursive nested object is found, it will be replaced by the string **recursive**. Otherwise it would fail in because of infinite loop.
By using typecasting you can resolve your problem.
Just add the following lines to your return object:
$arrObj = array(yourReturnedObject);
You can also add a new key and value pair to it by using:
$arrObj['key'] = value;