将 PHP 对象转换为关联数组
Posted
技术标签:
【中文标题】将 PHP 对象转换为关联数组【英文标题】:Convert a PHP object to an associative array 【发布时间】:2011-05-19 17:38:53 【问题描述】:我正在将一个 API 集成到我的网站中,该 API 可以处理存储在对象中的数据,而我的代码是使用数组编写的。
我想要一个快速而简单的函数来将对象转换为数组。
【问题讨论】:
【参考方案1】:从谷歌第一次命中“php object to assoc array”我们得到了:
function object_to_array($data)
if (is_array($data) || is_object($data))
$result = [];
foreach ($data as $key => $value)
$result[$key] = (is_array($data) || is_object($data)) ? object_to_array($value) : $value;
return $result;
return $data;
来源是at codesnippets.joyent.com。
将其与json_decode & json_encode
的解决方案进行比较,这个似乎更快。这是一个随机基准(使用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
【讨论】:
就个人而言,我不喜欢为每个值调用函数的想法。我有一个类似的版本,但只有 3 行:function objectToArray($o) $a = array(); foreach ($o as $k => $v) $a[$k] = (is_array($v) || is_object($v)) ? objectToArray($v): $v; return $a;
这只是设置任何不是对象或数组的东西,除非必要,否则不会重复调用该方法。
@SpYk3HH:写你自己的答案?
“php object to assoc array”的第一个命中是***.com/questions/4345554/…
这个(以及来自@SpYk3HH 的版本)对我来说似乎比 json_encode 选项 (***.com/a/16111687/470749) 执行得更慢。我不知道为什么这些方法会更受欢迎。
@Ryan json 编码和解码不适用于浮点的 NaN 和 INFINITE 值,并且可能存在我无法想到的其他问题,但在许多情况下,它可能是一个更好的选择。至于优化,它需要的是上下文——让我插入我在这个主题上写的帖子evidentlycube.com/blog/game-optimization/when-to-optimize。 tl;博士是,不要优化不占用大量运行时间的东西,因为在整个应用程序的上下文中这些好处是毫无意义的。【参考方案2】:
只是打字
$array = (array) $yourObject;
来自Arrays:
如果将对象转换为数组,则结果是一个数组,其元素是对象的属性。键是成员变量名,有几个值得注意的例外:整数属性不可访问;私有变量在变量名前面加上类名;受保护的变量在变量名前有一个“*”。这些前置值在两边都有空字节。
示例:简单对象
$object = new StdClass;
$object->foo = 1;
$object->bar = 2;
var_dump( (array) $object );
输出:
array(2)
'foo' => int(1)
'bar' => int(2)
示例:复杂对象
class Foo
private $foo;
protected $bar;
public $baz;
public function __construct()
$this->foo = 1;
$this->bar = 2;
$this->baz = new StdClass;
var_dump( (array) new Foo );
输出(为清楚起见编辑了 \0s):
array(3)
'\0Foo\0foo' => int(1)
'\0*\0bar' => int(2)
'baz' => class stdClass#2 (0)
用var_export
代替var_dump
输出:
array (
'' . "\0" . 'Foo' . "\0" . 'foo' => 1,
'' . "\0" . '*' . "\0" . 'bar' => 2,
'baz' =>
stdClass::__set_state(array(
)),
)
以这种方式进行类型转换不会对对象图进行深度转换,您需要应用空字节(如手册引用中所述)来访问任何非公共属性。因此,这在转换 StdClass 对象或仅具有公共属性的对象时效果最佳。对于快速和肮脏的(你要求的)它很好。
另请参阅这篇深入的博文:
Fast PHP Object to Array conversion【讨论】:
还可以考虑ArrayAccess
接口,也许与此解决方案结合使用。 php.net/manual/en/class.arrayaccess.php
如果您有整数键,则将被转换为字符串,这可能会导致大问题。例如。 [1 => "one"]
变为 ["1" => "one"]
@Howie Typecasting 与 (array)
和 (object)
在 PHP 4.3 之后的所有版本中可靠且相同。见3v4l.org/X6lhm。如果你得到一个语法错误,你做错了什么。
@Howie 请参阅Changelog section for empty
。在 5.5 之前,您不能使用带有 empty
的表达式。这与类型转换完全无关;)
类型转换。是的。类型 Freakin CAST!好的。 +1【参考方案3】:
类型将您的对象转换为数组。
$arr = (array) $Obj;
它会解决你的问题。
【讨论】:
不,如果您有私有或受保护的属性,它不会。 最简单的解决方案。谢谢【参考方案4】:这里有一些代码:
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;
【讨论】:
最适合我(但我需要删除 'xxx' 并返回 $data)【参考方案5】:当您从数据库获取数据作为对象时,您可能希望这样做:
// 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;
【讨论】:
有一个接受的答案,有 41 个赞成票,而不是 1 或 10、41。你的答案增加了什么? 而计数器是不必要的包含【参考方案6】:此处发布的所有其他答案仅适用于公共属性。下面是一种使用反射和 getter 处理类似 JavaBeans 的对象的解决方案:
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;
【讨论】:
是的,但是......如果你使用对象/数组作为变量,这也是所有这些导致的,为什么你需要除了public
属性之外的任何东西?跨度>
@SpYk3HH:我没有问这个问题。我什至不知道为什么有人会更喜欢数组而不是对象。
嗯,我通常更喜欢将查询结果转换为数组,只是为了提供一个统一的“列表”用于循环,因为应用程序中必须“循环”的大多数其他东西往往是数组。只是让编写“通用循环方法”变得容易。通常,如果我正在使用一个对象,我不会遍历它的属性,而是将它用作一个对象并根据需要使用这些属性。
“为什么有人更喜欢数组而不是对象” 我想编写一个方法,它使用 foreach 循环遍历对象属性的值,以将它们写入 excel 文件。我希望这个方法独立于对象,以便我可以将它与不同的数组一起使用。因此我的对象需要一个 _toArray() 方法【参考方案7】:
如果您的对象属性是公开的,您可以这样做:
$array = (array) $object;
如果它们是私有的或受保护的,它们将在阵列上具有奇怪的键名。因此,在这种情况下,您将需要以下功能:
function dismount($object)
$reflectionClass = new ReflectionClass(get_class($object));
$array = array();
foreach ($reflectionClass->getProperties() as $property)
$property->setAccessible(true);
$array[$property->getName()] = $property->getValue($object);
$property->setAccessible(false);
return $array;
【讨论】:
如果您的财产受到保护,setAccessible(false) 会将其改回受保护的可见性吗?还是会将其设为私有? 我找到的唯一解决方案,它适用于受保护的属性。谢谢 私有和受保护变量的最佳解决方案! 这里是 $property->setAccessible(false);将在每个属性上执行 - 即使它是公开的...... 我想另一种方法是将其转换为数组,然后从 Private 属性中去除文本前缀。不那么危险,因为您的方法有将公共属性设置为私有的风险【参考方案8】:您可以依靠 JSON 编码/解码函数的行为将深度嵌套的对象快速转换为关联数组:
$array = json_decode(json_encode($nested_object), true);
【讨论】:
如果您想要全深度递归转换(当然不介意性能不佳),这是最好的解决方案 顺便说一句,这在 php 5.5 上似乎不再起作用,您将再次返回一组对象 尊敬的,我认为它仍然有效...不要忘记将第二个参数设置为 true。 第二个参数解决了这个问题,适用于 PHP 5.6.25。谢谢! @sics(, @celsowm):您可以通过在您的类中实现 JsonSerializable 来控制要导出的内容(也:如何):php.net/manual/en/class.jsonserializable.php【参考方案9】:get_object_vars($obj)
呢?如果您只想访问对象的公共属性,这似乎很有用。
见get_object_vars。
【讨论】:
【参考方案10】:class Test
const A = 1;
public $b = 'two';
private $c = test::A;
public function __toArray()
return call_user_func('get_object_vars', $this);
$my_test = new Test();
var_dump((array)$my_test);
var_dump($my_test->__toArray());
输出
array(2)
["b"]=>
string(3) "two"
["Testc"]=>
int(1)
array(1)
["b"]=>
string(3) "two"
【讨论】:
这个解决方案的优缺点?声明为 class Test const A = 1; 的类呢?公共 $parent = new Test(); 【参考方案11】:转换和去除烦人的星星:
$array = (array) $object;
foreach($array as $key => $val)
$new_array[str_replace('*_', '', $key)] = $val;
可能会比使用反射便宜。
【讨论】:
【参考方案12】:这是我将 PHP 对象转换为关联数组的递归 PHP 函数:
// ---------------------------------------------------------
// ----- 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;
// ---------------------------------------------------------
// ---------------------------------------------------------
使用示例:
// ---- 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);
【讨论】:
.. 或 oneliner:$new_arr1 = (array) $my_object;
oneliner 版本比较浅,所以不等价。【参考方案13】:
将 stdClass 转换为数组的自定义函数:
function objectToArray($d)
if (is_object($d))
// Gets the properties of the given object
// with get_object_vars function
$d = get_object_vars($d);
if (is_array($d))
/*
* Return array converted to object
* Using __FUNCTION__ (Magic constant)
* for recursive call
*/
return array_map(__FUNCTION__, $d);
else
// Return array
return $d;
另一个将 Array 转换为 stdClass 的自定义函数:
function arrayToObject($d)
if (is_array($d))
/*
* Return array converted to object
* Using __FUNCTION__ (Magic constant)
* for recursive call
*/
return (object) array_map(__FUNCTION__, $d);
else
// Return object
return $d;
用法示例:
// Create new stdClass Object
$init = new stdClass;
// Add some test data
$init->foo = "Test data";
$init->bar = new stdClass;
$init->bar->baaz = "Testing";
$init->bar->fooz = new stdClass;
$init->bar->fooz->baz = "Testing again";
$init->foox = "Just test";
// Convert array to object and then object back to array
$array = objectToArray($init);
$object = arrayToObject($array);
// Print objects and array
print_r($init);
echo "\n";
print_r($array);
echo "\n";
print_r($object);
【讨论】:
【参考方案14】:$Menu = new Admin_Model_DbTable_Menu();
$row = $Menu->fetchRow($Menu->select()->where('id = ?', $id));
$Addmenu = new Admin_Form_Addmenu();
$Addmenu->populate($row->toArray());
【讨论】:
我假设这个答案是针对 Doctrine(或类似)记录的。【参考方案15】:用途:
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;
它返回一个没有特殊字符和类名的数组。
【讨论】:
【参考方案16】:这里我创建了一个 objectToArray() 方法,它也适用于递归对象,例如当$objectA
包含再次指向$objectA
的$objectB
时。
此外,我使用 ReflectionClass 将输出限制为公共属性。如果您不需要它,请摆脱它。
/**
* Converts given object to array, recursively.
* Just outputs public properties.
*
* @param object|array $object
* @return array|string
*/
protected function objectToArray($object)
if (in_array($object, $this->usedObjects, TRUE))
return '**recursive**';
if (is_array($object) || is_object($object))
if (is_object($object))
$this->usedObjects[] = $object;
$result = array();
$reflectorClass = new \ReflectionClass(get_class($this));
foreach ($object as $key => $value)
if ($reflectorClass->hasProperty($key) && $reflectorClass->getProperty($key)->isPublic())
$result[$key] = $this->objectToArray($value);
return $result;
return $object;
为了识别已经使用的对象,我在这个(抽象)类中使用了一个受保护的属性,名为$this->usedObjects
。如果找到递归嵌套对象,则将其替换为字符串**recursive**
。否则会因为无限循环而失败。
【讨论】:
$usedObjects
在开始时没有初始化,因此多次调用它会在以后的调用中给出不正确的结果。此外,您不会在最后释放它,因此您的对象永远不会从内存中删除。【参考方案17】:
要将对象转换为数组,只需显式转换:
$name_of_array = (array) $name_of_object;
【讨论】:
【参考方案18】:对“众所周知”代码的一些改进
/*** mixed Obj2Array(mixed Obj)***************************************/
static public function Obj2Array($_Obj)
if (is_object($_Obj))
$_Obj = get_object_vars($_Obj);
return(is_array($_Obj) ? array_map(__METHOD__, $_Obj) : $_Obj);
// BW_Conv::Obj2Array
请注意,如果函数是类的成员(如上),您必须将 __FUNCTION__
更改为 __METHOD__
【讨论】:
【参考方案19】:首先,如果您需要来自对象的数组,您可能应该首先将数据构成为数组。想一想。
不要使用foreach
语句或 JSON 转换。如果您计划这样做,那么您再次使用的是数据结构,而不是对象。
如果您真的需要它,请使用面向对象的方法来获得干净且可维护的代码。例如:
对象作为数组
class PersonArray implements \ArrayAccess, \IteratorAggregate
public function __construct(Person $person)
$this->person = $person;
// ...
如果您需要所有属性,请使用传输对象:
class PersonTransferObject
private $person;
public function __construct(Person $person)
$this->person = $person;
public function toArray()
return [
// 'name' => $this->person->getName();
];
【讨论】:
所以我会手动将想要的属性分配给数组值吗?是的,这是可能的,但我希望我可以通过在我的对象中实现一个 _toArray() 方法来避免这种情况,该方法无需手动添加每个属性即可完成。【参考方案20】:由于很多人因为无法动态访问对象的属性而发现这个问题,我只是指出你可以在 PHP 中做到这一点:$valueRow->"valueName"
在上下文中(为了便于阅读,删除了 html 输出):
$valueRows = json_decode("..."); // Rows of unordered values decoded from a JSON object
foreach ($valueRows as $valueRow)
foreach ($references as $reference)
if (isset($valueRow->$reference->valueName))
$tableHtml .= $valueRow->$reference->valueName;
else
$tableHtml .= " ";
【讨论】:
【参考方案21】:你可以很容易地使用这个函数来得到结果:
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;
使用 PHP 5 或更高版本。
【讨论】:
【参考方案22】:这个答案只是这篇文章不同答案的结合,但它是将具有简单值或数组的公共或私有属性的PHP对象转换为关联数组的解决方案......
function object_to_array($obj)
if (is_object($obj))
$obj = (array)$this->dismount($obj);
if (is_array($obj))
$new = array();
foreach ($obj as $key => $val)
$new[$key] = $this->object_to_array($val);
else
$new = $obj;
return $new;
function dismount($object)
$reflectionClass = new \ReflectionClass(get_class($object));
$array = array();
foreach ($reflectionClass->getProperties() as $property)
$property->setAccessible(true);
$array[$property->getName()] = $property->getValue($object);
$property->setAccessible(false);
return $array;
【讨论】:
【参考方案23】:@SpYk3HH 的短解
function objectToArray($o)
$a = array();
foreach ($o as $k => $v)
$a[$k] = (is_array($v) || is_object($v)) ? objectToArray($v): $v;
return $a;
【讨论】:
【参考方案24】:你也可以使用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);
【讨论】:
【参考方案25】:你也可以在 PHP 中创建一个函数来转换一个对象数组:
function object_to_array($object)
return (array) $object;
【讨论】:
【参考方案26】:通过使用类型转换,您可以解决问题。 只需将以下行添加到您的返回对象:
$arrObj = array(yourReturnedObject);
您还可以使用以下方法向其添加新的键值对:
$arrObj['key'] = value;
【讨论】:
【参考方案27】:这是我的建议,如果您的对象中包含私有成员:
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;
【讨论】:
【参考方案28】:对于您的情况,如果您使用“装饰器”或“日期模型转换”模式是正确/美丽的。例如:
你的模型
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;
装饰器
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(),
];
用法
$car = new Car();
$car->setType('type#');
$car->setModel('model#1');
$car->setColor(255);
$carDecorator = new CarArrayDecorator($car);
$carResponseData = $carDecorator->getArray();
这样代码会更漂亮更正确。
【讨论】:
【参考方案29】:我认为使用特征来存储对象到数组的转换逻辑是一个好主意。一个简单的例子:
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());
【讨论】:
【参考方案30】:不是一个新的解决方案,但包括可用的 toArray 方法转换
function objectToArray($r)
if (is_object($r))
if (method_exists($r, 'toArray'))
return $r->toArray(); // returns result directly
else
$r = get_object_vars($r);
if (is_array($r))
$r = array_map(__FUNCTION__, $r); // recursive function call
return $r;
【讨论】:
以上是关于将 PHP 对象转换为关联数组的主要内容,如果未能解决你的问题,请参考以下文章