【问题标题】:PHP display nested Object with array of other Object as 1 nested arrayPHP将嵌套对象与其他对象数组显示为1个嵌套数组
【发布时间】:2018-03-08 08:44:18
【问题描述】:

我有一个带有受保护属性的大对象,一个属性可以是其他对象的数组。我的目标是将整个对象打印为单个嵌套数组。所以我需要将对象转换为数组。

我已经尝试过:

$result = (array) $object;

但这只会将最高级别的对象转换为数组,并且会用奇怪的问号符号混淆我的受保护属性名称。

我也尝试过类似的方法,但这只是返回一个空数组:

$result=json_decode(json_encode($object), true);

这是我的对象的样子:

object(Handling\Model\SearchBooking\Booking)[133]
  protected 'jabooknr' => string '018024709' (length=9)
  protected 'jitsbooknr' => string '' (length=9)
  protected 'status' => string 'Y' (length=1)
  protected 'platform' => int 4
  protected 'agentid' => string '' (length=6)
  protected 'paymentInfo' => null
  protected 'transports' => 
    array (size=2)
      0 => 
        object(Handling\Model\SearchBooking\Transport)[145]
          protected 'depdate' => 
            object(DateTime)[146]
              public 'date' => string '2016-12-06 00:00:00.000000' (length=26)
              public 'timezone_type' => int 3
              public 'timezone' => string 'UTC' (length=3)
          protected 'carriercode' => string 'TB' (length=2)
          protected 'carriernumber' => string '2067' (length=4)
          protected 'brochure' => string '' (length=6)
          protected 'pax' => 
            array (size=2)
              0 => 
                object(Handling\Model\SearchBooking\Pax)[147]
                  protected 'id' => int 1
                  protected 'title' => string 'MRS' (length=3)
                  protected 'firstname' => string 'MA' (length=7)
                  protected 'name' => string 'BEN' (length=5)
                  protected 'age' => int 58
                  protected 'luggage' => int 20
                  protected 'handLuggage' => null
              1 => 
                object(Handling\Model\SearchBooking\Pax)[148]
                  protected 'id' => int 2
                  protected 'title' => string 'MR' (length=2)
                  protected 'firstname' => string 'P' (length=6)
                  protected 'name' => string 'FT' (length=4)
                  protected 'age' => int 60
                  protected 'luggage' => int 20
                  protected 'handLuggage' => null
          protected 'departureAirport' => string 'BRU' (length=3)
          protected 'arrivalAirport' => string 'AGP' (length=3)
      1 => 
        object(Handling\Model\SearchBooking\Transport)[149]
          protected 'depdate' => 
            object(DateTime)[150]
              public 'date' => string '2016-12-13 00:00:00.000000' (length=26)
              public 'timezone_type' => int 3
              public 'timezone' => string 'UTC' (length=3)
          protected 'carriercode' => string 'TB' (length=2)
          protected 'carriernumber' => string '2068' (length=4)
          protected 'brochure' => string '' (length=6)
          protected 'pax' => 
            array (size=2)
              0 => 
                object(Handling\Model\SearchBooking\Pax)[151]
                  protected 'id' => int 1
                  protected 'title' => string 'MRS' (length=3)
                  protected 'firstname' => string 'MANE' (length=7)
                  protected 'name' => string 'BN' (length=5)
                  protected 'age' => int 58
                  protected 'luggage' => int 20
                  protected 'handLuggage' => null
              1 => 
                object(Handling\Model\SearchBooking\Pax)[152]
                  protected 'id' => int 2
                  protected 'title' => string 'MR' (length=2)
                  protected 'firstname' => string 'PIRE' (length=6)
                  protected 'name' => string 'FYT' (length=4)
                  protected 'age' => int 60
                  protected 'luggage' => int 20
                  protected 'handLuggage' => null
          protected 'departureAirport' => string 'AGP' (length=3)
          protected 'arrivalAirport' => string 'BRU' (length=3)
  protected 'extraLuggage' => null

编辑

我的班级中有一个方法,我可以在其中“找到”如下所示的结果:

public function findBooking()
{
    //here happens a bunch of logic to get the right result

    var_dump($object); exit; // this is the result that is show above        

    return $object;
}

【问题讨论】:

  • 在正常使用情况下,您无法打印受保护的内容,因为它在课堂外不可见。你可以用反射来做,但这不是微不足道的,如果你想看一个例子,你可以在这里查看我的调试类github.com/ArtisticPhoenix/Evo/blob/master/Evo/Debug.php 虽然你必须删除顶部的环境检查才能工作(因为我没有'尚未将其分离到它自己的项目中)
  • 基本上它们不在课堂之外的可见范围内,如果您将这些更改为public 进行测试,您会看到情况就是这样。这是保护的重点......
  • @ArtisticPhoenix 我不认为这是一个问题,我只需要一种方法将我的结果转换为单个数组以将其作为 JSON 返回,因为它实际上是一个 API 调用响应
  • 不是这样的。唯一的另一种方法是在类中编写一个函数,称为toJson()
  • @ArtisticPhoenix 是的,这是目标,但我不知道如何将嵌套对象转换为数组

标签: php arrays object


【解决方案1】:

有几个问题让这变得困难。

  • 属性可见性(私有、受保护)在尝试在课堂外读取它们时可能会导致问题,正确的。这是预期的行为,因为这就是不使用 public 的关键。

  • 类不同。它们定义明确,我们提前了解它们,但它们过于多样化,无法解释所有属性名称,至少不会浪费大量精力。更不用说将它们定义为“硬编码”会在以后给您带来麻烦,因为这会使维护变得困难。例如,如果其中一个包进行了更新,并且您已经在其中编码了属性名称,那么如果它们更改它们,您可能会遇到问题。除此之外,鉴于这些属性不是公共“API”类的一部分,而是内部的一部分,因此更改它们并非不合理。

  • 属性可以包含多种数据类型,包括其他类或对象。这可能会使处理变得困难。

  • 类是其他包/框架的一部分,编辑它们是不切实际的,这限制了我们在这些类之外工作。

因此,鉴于这些困难,我建议使用反射来访问受保护的属性。反射允许您检查类(和其他东西)的定义。

function jsonSerialize($obj){
    return json_encode(toArray($obj));
}

function toArray($obj){
    $R = new ReflectionObject($obj);
    $proerties = $R->getProperties();
    $data = [];

    foreach($proerties as $k => $v){
        $v->setAccessible(true);
        $property = $v->getName();
        $value = $v->getValue($obj);

        if(!is_object($value)){
            $data[$property] = $value;    
        }else if( is_a($obj,'\\DateTime')){
            //if its a descendant of Datetime, get a formatted date.
            // you can add other special case classes in this way
            $data[$property] = $value->format('Y-m-d H:i:s');
        }else{
           $data[$property] = toArray($value); //call recursively
        }
    }
    return $data;
}

假设我们有这些类

class foo{
    private $bar; //private nested object

    public function __construct(){
        $this->bar = new bar();

    }

}

class bar{
    private $something = 'hello';
}

$obj = new foo;

echo jsonSerialize($obj);

在沙盒中查看它here

输出:

{"bar":{"something":"hello"}}

另外值得注意的是,我们对DateTime 类有一个特殊的考虑。我们只希望日期(可能)以某种标准方式格式化,而不是获取它的所有属性。所以通过使用is_a()(我是老派)我们可以判断对象$value是否有一个给定的类作为它的祖先。然后我们就进行格式化。

这样的特殊情况可能有一些,所以我想提一下如何处理。

【讨论】:

  • 感谢您非常详细的回复,但我的目标不是保存或重新创建我的对象的状态。我的目标是简单地将我的对象转换为一个数组,以便我可以将它作为 json 返回,例如
  • 好吧,正如我所说,你不能在课堂外这样做,因为私有和受保护的东西是不可见的。如果您执行(Array),它可能会显示它,但它会在键中放入一些垃圾。正如我所说,最好的方法是编写一个函数来返回类中的json,你可以使用JsonSerializable interface php.net/manual/en/class.jsonserializable.php
  • 但是您仍然必须编写执行此操作的方法,这在没有看到您的类的情况下有点悬而未决。
  • 我知道我必须编写方法,但我不知道如何将我的对象实际转换为 json,而且我不明白 jsonserializable 类的作用。我会尝试一些东西,最终我会弄明白的,谢谢:)
  • 嗯,你可以只构建一个数组$data = ['foo' => $this->foo],然后return json_encode($data) 或者你可以使用反射之类的东西来获取类属性的列表并遍历它们。如果它是一个嵌套对象,给它同样的方法,然后做$data = ['obj' => $this->obj->jsonSerialize()]
【解决方案2】:

虽然这是一个古老的查询,但大多数答案并不容易理解。所以我试图简化这个特定问题的代码。

获取 JSON 对象的更简洁的方法是实现 JsonSerializable 接口。

class Booking  implements JsonSerializable
{
protected $jabooknr;
protected $platform;
//Other attributes ....

//Array of tronsport
protected $transports;
protected $extraLuggage;

    public function jsonSerialize()
    {
        return [
            'jabooknr'=> $this->jabooknr,
            'platform'=> $this->platform,

            'transports' => [json_encode($this->transports)
                ],

            '$extraLuggage' => $this->extraLuggage
        ];
    }
    public function __construct($jabooknr, $platform){
        $this->jabooknr = $jabooknr;
        $this->platform = $platform;
        $this->transports=[new Transport()];
    }
}
class Transport implements JsonSerializable{
    protected $carriercode;
    protected $carriernumber;
    //Array of Pax
    protected $pax ;
    public function jsonSerialize()
    {
        return [
            'carriercode'=> $this->carriercode,
            'carriernumber'=> $this->carriernumber
        ];
    }
}
$booking = new Booking('018024709',25);
echo json_encode($booking);

【讨论】:

    猜你喜欢
    • 2014-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-27
    • 1970-01-01
    • 2022-01-08
    • 2020-03-11
    相关资源
    最近更新 更多