ChatGPT解决这个技术问题 Extra ChatGPT

将 PHP 对象转换为关联数组

我正在将一个 API 集成到我的网站中,该 API 使用存储在对象中的数据,而我的代码是使用数组编写的。

我想要一个快速而简单的函数来将对象转换为数组。


P
Peter Mortensen

只是打字

$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 对象或仅具有公共属性的对象时效果最佳。对于快速和肮脏的(你所要求的)它很好。

另请参阅这篇深入的博客文章:

快速 PHP 对象到数组的转换


还要考虑 ArrayAccess 接口,可能与此解决方案结合使用。 php.net/manual/en/class.arrayaccess.php
如果您有整数键,则将转换为字符串,这可能会导致大问题。例如 [1 => "one"] 变成 ["1" => "one"]
@Howie 使用 (array)(object) 进行类型转换在 PHP 4.3 之后的所有版本中都可靠且相同。请参阅3v4l.org/X6lhm。如果你得到一个语法错误,你做错了什么。
@Howie 看到 Changelog section for empty。在 5.5 之前,您不能使用带有 empty 的表达式。这与类型转换完全无关;)
类型转换。是的。类型 Freakin CAST!好的。 +1
E
Elia Weiss

您可以依靠 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
8
8 revs, 6 users 43%

从谷歌第一次命中“PHP 对象到关联数组”,我们有这样的:

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

源是 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”的第一个命中是 stackoverflow.com/questions/4345554/…
这(以及来自@SpYk3HH 的版本)对我来说似乎比 json_encode 选项(stackoverflow.com/a/16111687/470749)执行得更慢。我不知道为什么这些方法会更可取。
@Ryan json 编码和解码不适用于浮点的 NaN 和 INFINITE 值,并且可能存在我无法想到的其他问题,但在许多情况下,它可能是更好的选择。至于优化,它需要的是上下文 - 让我插入我在这个主题 evidentlycube.com/blog/game-optimization/when-to-optimize 上写的一篇文章。 tl;博士是,不要优化不占用大量运行时间的东西,因为这些好处在整个应用程序的上下文中毫无意义。
B
Bhargav Nanekalva

如果您的对象属性是公开的,您可以执行以下操作:

$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);将在每个财产上执行 - 即使它是公开的......
我想另一种方法是将其转换为数组,然后从私有属性中去除文本前缀。不那么危险,因为您的方法有将公共属性设置为私有的风险
P
Peter Mortensen

get_object_vars($obj) 呢?如果您只想访问对象的公共属性,这似乎很有用。

请参阅 get_object_vars


I
Isius
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(); }
d
doctorsherlock

类型将您的对象转换为数组。

$arr =  (array) $Obj;

它会解决你的问题。


不,如果您有私有或受保护的财产,它不会。
最简单的解决方案。谢谢
P
Peter Mortensen

这是一些代码:

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)
P
Peter Mortensen

此处发布的所有其他答案仅适用于公共属性。这是一种使用反射和 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;
}

是的,但是...如果您使用 Object/Array 作为变量,这也是所有这些导致的,为什么除了 public 属性之外还需要其他属性?
@SpYk3HH:我没有问这个问题。我什至不知道为什么有人会更喜欢数组而不是对象。
嗯,我经常更喜欢将查询结果转换为数组,只是为了提供一个统一的“列表”用于循环,因为应用程序中必须“循环”的大多数其他东西往往是数组。只是让编写“通用循环方法”变得容易。通常,如果我正在使用一个对象,我不会遍历它的属性,而是将它用作对象并根据需要使用这些属性。
“为什么有人更喜欢数组而不是对象”我想编写一个方法,该方法使用 foreach 循环遍历对象属性的值,以将它们写入 excel 文件。我希望这个方法独立于对象,以便我可以将它与不同的数组一起使用。因此我的对象需要一个 _toArray() 方法
P
Peter Mortensen

要将对象转换为数组,只需显式转换:

$name_of_array = (array) $name_of_object;

P
Peter Mortensen

您还可以在 PHP 中创建一个函数来转换对象数组:

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

S
Sebastian

利用:

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

它返回一个没有特殊字符和类名的数组。


我从不推荐使用括号作为模式分隔符。它太容易欺骗开发人员/审阅者的眼睛
P
Peter Mortensen

首先,如果您需要来自对象的数组,您可能应该首先将数据构成为数组。想想看。

不要使用 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() 方法来避免这种情况,该方法无需手动添加每个属性就可以实现这一点。
P
Peter Mortensen

您可以轻松地使用此函数来获得结果:

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 或更高版本。


P
Peter Mortensen

这是我将 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 版本很浅,因此不等效。
P
Peter Mortensen

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

A
Abdul Rehman

@SpYk3HH 的简短解决方案

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

    return $a;
}

A
Andrey Nilov

您也可以使用 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);

P
Peter Mortensen

当您从数据库获取数据作为对象时,您可能希望这样做:

// 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。你的答案增加了什么?
而柜台是不必要的包含
P
Peter Mortensen

这个答案只是这篇文章不同答案的结合,但它是将具有简单值或数组的公共或私有属性的 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;
}

G
Gilbert BENABOU

“众所周知”代码的一些改进

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


D
Daniel Abyan

对于您的情况,如果您使用“装饰器”或“日期模型转换”模式是正确/美丽的。例如:

你的模型

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

所以它会更漂亮,更正确的代码。


P
Peter Mortensen

转换和去除恼人的星星:

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

可能它会比使用反射便宜。


K
Karol Gasienica

我的建议是,如果您的对象中有对象甚至是私有成员:

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

P
Peter Mortensen

由于很多人发现这个问题是因为动态访问对象的属性有问题,所以我只想指出您可以在 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 .= " ";
        }
    }
}

P
Peter Mortensen

通过使用类型转换,您可以解决您的问题。只需将以下行添加到您的返回对象:

$arrObj = array(yourReturnedObject);

您还可以使用以下方法向其添加新的键和值对:

$arrObj['key'] = value;

P
Peter Mortensen

我认为使用特征存储对象到数组的转换逻辑是一个好主意。一个简单的例子:

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

l
ling

我使用它(需要具有正确键的递归解决方案):

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

用法示例,如下代码:

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)

将打印这个:

array(2) {
  ["bb"] => array(1) {
    ["two"] => int(22)
  }
  ["one"] => int(11)
}


我们如何升级您的函数以支持具有对象数组的对象?
它是一个旧的 - 但合理的答案,只是指出如果我们真的想停止递归,需要将 deep 参数传递给递归函数调用。
S
Saurabh Chandra Patel
$Menu = new Admin_Model_DbTable_Menu(); 
$row = $Menu->fetchRow($Menu->select()->where('id = ?', $id));
$Addmenu = new Admin_Form_Addmenu(); 
$Addmenu->populate($row->toArray());

我假设这个答案是针对 Doctrine(或类似)记录的。
A
Armin

在这里,我创建了一个 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 在开始时未初始化,因此多次调用它会在以后的调用中给出不正确的结果。此外,您不会在最后释放它,因此您的对象永远不会从内存中删除。