【问题标题】:json encode is not working with array of objectsjson 编码不适用于对象数组
【发布时间】:2012-03-29 20:00:12
【问题描述】:

我想将对象数组转换为 json 编码,我这样做

$allVisits = $mapper->getAllVisits($year, $month);
echo json_encode($allVisits);

这里是 getAllVisists 方法

 function getAllVisits($year, $month) {
    $where = array(
        'year = ?' => $year,
        'month = ?' => $month
    );
     $resultSet = $this->getDbTable()->fetchAll( $where);
    $visitsEntries = array();
    foreach ($resultSet as $row) {

        $entry = new Visits_Model_Visit();
        $entry->setId($row->visit_id)
                ->setDay($row->day)
                ->setDate($row->date)
                ->setTarget($row->target)
                ->setStatus($row->visit_status)
                ->setTime($row->visit_time);

        $visitsEntries[] = $entry;
    }
    return $visitsEntries;
}

当我回显 $allVisits 的大小时,它会返回正确数量的记录,但在 js 中接收到的值为空,如下所示 [{},{},{},{}]

编辑

当我 print_r($allVisists) brfore 编码它返回

Array
(
    [0] => Visits_Model_Visit Object
        (
            [day:private] => sunday
            [date:private] => 2012-03-06
            [target:private] => شسي
            [id:private] => 1
            [status:private] => 0
            [time:private] => 12:00:00
        )

    [1] => Visits_Model_Visit Object
        (
            [day:private] => sunday
            [date:private] => 2012-03-06
            [target:private] => clinnics
            [id:private] => 4
            [status:private] => 0
            [time:private] => 00:00:00
        )

    [2] => Visits_Model_Visit Object
        (
            [day:private] => Tuesday
            [date:private] => 2012-03-06
            [target:private] => clinnics
            [id:private] => 5
            [status:private] => 0
            [time:private] => 00:00:00
        )

    [3] => Visits_Model_Visit Object
        (
            [day:private] => Wednesday
            [date:private] => 2012-03-28
            [target:private] => ??????? ???????
            [id:private] => 7
            [status:private] => 0
            [time:private] => 12:00:00
        )

)

【问题讨论】:

  • 在致电json_encode之前,您是否尝试过print_r($allVisits)
  • 正确打印出数组

标签: php json zend-framework encoding


【解决方案1】:

您正在将json_encode 用于没有任何公共成员的对象。 json_encode 仅适用于它可以“看到”的成员,这就是为什么它们是空的。

从 PHP 5.4 开始,您可以使用JsonSerializable interface 来控制为json_encode 提供哪些数据,例如:

class Visits_Model_Visit implements JsonSerializable {
    ...
    public function jsonSerialize() {
        return (object) get_object_vars($this);
    }
    ...
}

如果您低于 5.4,您也可以在不从接口扩展的情况下实现该功能,然后手动分配正确的值:

$visitsEntries[] = $entry->jsonSerialize();

希望这会有所帮助。

【讨论】:

  • 如果你按照我下面的方法,你可以在早期版本的 PHP 中实现 JsonSerializable。
【解决方案2】:

正如 Ray 所说,如果您的类属性是受保护的或私有的,这些将不会被 json 化。

由于 PHP 5.4 不再使用注释的 toJson 方法,您可以通过实现 JsonSerializable 接口来指定将序列化哪些数据,因此 json_encode 知道如何处理。

/* PHP >= 5.4 only */
class Visits_Model_Visit implement JsonSerializable {
    public function jsonSerialize()
    {
        return array(
             'day' => $this->day,
             'date' => $this->date,
             'target' => $this->target,
             'id' => $this->id,
             'status' => $this->status,
        );
    }
}

【讨论】:

  • 支持 5.4。这将清理我的六个内部 api。手指交叉升级不会破坏我的服务器。
  • @arraintxo 我的公司刚刚升级到 php 5.3 :( 我没有得到 JsonSerializable 接口。
  • @Ray,我的解决方案允许您在 PHP 的早期版本中实现 JsonSerialable。
【解决方案3】:

默认情况下,json_encode() 只序列化对象的公共属性。将您想要序列化的所有属性公开是不是解决方案! PHP 5.4 及更高版本具有 JsonSerializable 接口,但我为早期版本的 PHP 提出了一个简单的解决方案。

由于 JsonSerializable 只是 PHP 5.4 及更高版本的一部分,请自行创建。

if (!interface_exists('JsonSerializable')) {
   interface JsonSerializable {
      public function jsonSerialize();
   }
}

这并不难,是吗?现在我们可以实现 JsonSerializable 而不用担心我们使用的是什么版本的 PHP!

class Visits_Model_Visit implements JsonSerializable {
    ...
    // Only put properties here that you want serialized.
    public function jsonSerialize() {
        return Array(
           'day'    => $this->day,
           'date'   => $this->date,
           'target' => $this->target,
           'id'     => $this->id,
           'status' => $this->status,
           'obj'    => $this->obj->jsonSerialize(), // example for other objects
           'time'   => $this->time
        );
    }
    ...
}

现在您只需调用 jsonSerialize() 即可获得一个关联数组,您可以使用 json_encode() 对其进行编码。

    ...
    $entry = new Visits_Model_Visit();
    $entry->setId($row->visit_id)
          ->setDay($row->day)
          ->setDate($row->date)
          ->setTarget($row->target)
          ->setStatus($row->visit_status)
          ->setTime($row->visit_time);

    $visitsEntries[] = $entry->jsonSerialize();
    ...

然后您可以致电json_encode($visitsEntries) 以获得您想要的结果。

[
   {
      "day":"sunday",
      "date":"2012-03-06",
      "target":"\u0634\u0633\u064a",
      "id":1,
      "status":0,
      "time":"12:00:00"
   },
   {
      "day":"sunday",
      "date":"2012-03-06",
      "target":"clinnics",
      "id":4,
      "status":0,
      "time":"00:00:00"
   },
   ...
]

【讨论】:

  • 为什么是数组?我想要对象 - 问题是“......对象数组”
  • 一个关联数组,因为当您在其上调用 json_encode() 时,它将转换为对象的正确 JSON 表示法。数组中的键将是“对象”属性名称,而值将是这些属性的值。我会用最终结果更新我的答案。
  • 更新我的评论:json_encode() 实际上不会检查您是否传入数组或对象,因此您必须将其显式转换为输出中需要的任何内容。所以数组很好,它只是我希望比实际更聪明的 PHP。
【解决方案4】:

对象的属性是私有的还是受保护的?如果是这样,json 编码在对象内部看不到它们。我通过在我需要序列化为 json 的对象中创建一个“toJson”方法来解决这个问题。在此方法中,我遍历对象属性并手动构造一个通用对象,然后将其传递给 json_encode。然后我从这个方法返回 Json 字符串。

不要只公开所有对象属性!!!!

【讨论】:

  • 同意。如果你不同意 Ray 的最后一点建议,那就大错特错了。
【解决方案5】:

对于那些正在寻找简单答案的人,与其他复杂的答案不同,我是一件艺术品:

json_encode(array(
    Protocol::PARAM_CODE => Protocol::CODE_SUCCESS,
    Protocol::PARAM_USER => (object)$user->jsonSerialize()
));

即使 $user->jsonSerialize() 输出 stdObject,json_encode 也是如此愚蠢,它不知道它是对象,所以你必须 明确地声明 并将其转换为 (object ) - 你不喜欢 PHP 的简单性吗?

【讨论】:

  • 没有。您引用的协议:: 类
  • @user431806 哦,它只是包含一些客户端-服务器通信协议常量的类。这并不重要,重要的部分只是您必须将 stdObject 类显式转换为 (object) 因为 json_encode 否则不会将其识别为对象。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-15
  • 2021-10-18
  • 2012-07-29
  • 2016-04-24
相关资源
最近更新 更多