2

我刚刚了解了 PHP 5.4 的这个奇特的新特性。 JsonSerializable!这非常适合我的应用程序。

我的应用程序使用 DateTime 对象,当我使用json_encode它们时,我得到以下信息(通过运行json_encode([new DateTime])):

[{"date":"2013-09-11 15:39:22","timezone_type":3,"timezone":"UTC"}]

根据timezone_type具体情况,timezone值可能会有所不同。我还没有找到在 JavaScript 中解析这个对象的好方法。

因此,我决定创建自己的 DateTime 类,并按照我的意愿将其序列化为 JSON。

class SerialDateTime extends DateTime implements JsonSerializable{

    public function jsonSerialize(){
        return ['timestamp' => $this->getTimestamp()];
    }
}

当我现在运行时json_encode([new SerialDateTime]),我得到了这个:

[{"timestamp":1378914190}]

这在 JavaScript 中更容易解析。

所以,我认为这是一个很好的解决方案,但我发现了一个问题。静态方法! SerialDateTime::createFromFormat返回一个DateTime对象!

如果我这样做:json_encode([SerialDateTime::createFromFormat('m/d/Y', '10/31/2011')]),我得到:

[{"date":"2011-10-31 15:46:07","timezone_type":3,"timezone":"UTC"}]

为什么会这样?为什么不SerialDateTime::createFromFormat给我一个SerialDateTime对象?!

我该如何解决这个问题,或者我是否需要覆盖in 中的所有静态方法?如果我这样做,我什至如何从该方法中创建一个新的?我怎样才能将对象“投射”到?DateTimeSerialDateTimeSerialDateTimecreateFromFormatDateTimeSerialDateTime

我想到了一个解决方法,但必须有更好的方法:

public static function createFromFormat($f, $t, $tz=NULL){
    $dateTime = call_user_func(
        array('SerialDateTime', 'parent::createFromFormat'),
        $f, $t, $tz
    );
    $ret = new self();
    return $ret->setTimestamp($dateTime->getTimestamp());
}

我可以使用__callStaticandreturn call_user_func_array(array(__CLASS__ , 'parent::'.__FUNCTION__), func_get_args());或其他东西吗?

太糟糕了,我不能神奇地转换DateTime为使用后期静态绑定

4

2 回答 2

3

就像您已经说过并尝试过的那样,覆盖静态方法。方法createFromFormat默认返回DateTime对象,所以你只需要修复返回部分,它就会返回你的对象SerialDateTime而不是DateTime.

class SerialDateTime extends DateTime implements JsonSerializable {

    public function jsonSerialize()
    {
        return ['timestamp' => $this->getTimestamp()];
    }

    public static function createFromFormat($format, $time, $timezone = null)
    {
        if ($timezone) {
            $dt = parent::createFromFormat($format, $time, $timezone);
        } else {
            $dt = parent::createFromFormat($format, $time);
        }

        return new self($dt->format(self::W3C));
    }

}

echo json_encode(new SerialDateTime);
echo json_encode(SerialDateTime::createFromFormat('Y', '2013'));

不管你如何调用静态方法createFromFormat,它总是会返回DateTime对象;所以你所有自动重写静态方法的想法都会失败,因为你需要用新的逻辑(返回其他对象的实例)来修改方法,而这不能通过 auto-call-method-magic-or-something 来实现。

DateTime::createFromFormat如果在以下方法中实现后期静态绑定,那就太好了:

public static function createFromFormat($format, $time, $timezone = null)
{
    // logic of converting $time from format $format to some default format 
    return new static($newTime);
}

...但不是 ;(源代码

于 2013-09-12T13:36:14.390 回答
1

所以,我会在这里发布我的答案。

在我看来,覆盖静态函数createFromFormat是处理您的问题的最佳方法。

因为:

  • 您的代码将保持干净(没有任何不必要的call_user_func
  • 重写父类方法并将类逻辑保留在类中是正确的。
  • 您的课程SerialDateTime将进一步可重用。(如果你只想导入类代码)

尽管没有必要覆盖所有方法(除非您实现接口)。仅覆盖您需要的那些。

于 2013-09-11T16:52:21.513 回答