我刚刚了解了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
对象?!
如何解决此问题,或者是否需要覆盖DateTime
中SerialDateTime
的所有静态方法?如果我这样做,我怎样才能从SerialDateTime
方法中制作新的createFromFormat
?我怎样才能"演员"一个DateTime
对象SerialDateTime
?
我想到了一种解决方法,但必须有更好的方法:
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());
}
我可以使用__callStatic
和return call_user_func_array(array(__CLASS__ , 'parent::'.__FUNCTION__), func_get_args());
或其他什么吗?
太糟糕了,我无法将DateTime
神奇地转换为使用late static bindings。
答案 0 :(得分: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-来完成或出头。
如果在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);
}
......但事实并非如此;(Source code
答案 1 :(得分:1)
所以,我会在这里发布我的答案。
在我看来,覆盖静态函数createFromFormat
是处理问题的最佳方法。
由于:
call_user_func
)SerialDateTime
将进一步重复使用。 (如果您只想导入类代码)虽然覆盖所有方法(除非实现接口),但没有必要。仅覆盖您需要的那些。