我有一个 WordPress 插件,我们正在将托管从 PHP 7 升级到 8。我们有一个函数,可以从会话中的序列化日期字符串创建一个 DateTime 对象,并使用 DateTime
diff
函数将其与现在进行比较。在 PHP 7 中这是可行的(例如给出 1 秒)。在 PHP 8 中,它给我们负一年加上 11 个月、29 天、23 小时、零(!)分钟和 1 秒!
我正在使用 PHP CLI 运行以下脚本。
<?php
$d = new DateTime();
echo '$d->format("r"): ' . $d->format('r') . "\n";
sleep(1);
$n = new DateTime( $d->format('r') );
$diff_d = $d->diff( new DateTime() );
$diff_n = $n->diff( new DateTime() );
echo "\n";
echo 'print_r($diff_d)' . "\n";
print_r($diff_d);
echo "\n";
echo 'print_r($diff_n)' . "\n";
print_r($diff_n);
echo "\n";
echo 'd' . "\n";
print_r($d);
echo "\n";
echo 'n' . "\n";
print_r($n);
我可以看到如何解决问题的特定实例(我们可能应该将 Unix 时间戳放入会话中,而不是日期字符串)。但我担心我不能再依赖日期差异函数,因为它在其他地方使用 - 或者它是否从字符串创建 DateTime 对象,这更令人担忧。
PHP 7 上的输出
上面的脚本位于 foo.php 中。在 CentOS 7 服务器上运行。首先我显示 PHP 版本,然后运行脚本。这个输出对我来说看起来是正确的。
$ php --version
PHP 7.3.33 (cli) (built: Nov 16 2021 11:18:28) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.33, Copyright (c) 1998-2018 Zend Technologies
$ php -f foo.php
$d->format("r"): Tue, 24 May 2022 17:35:16 +0300
print_r($diff_d)
DateInterval Object
(
[y] => 0
[m] => 0
[d] => 0
[h] => 0
[i] => 0
[s] => 1
[f] => 0.000213
[weekday] => 0
[weekday_behavior] => 0
[first_last_day_of] => 0
[invert] => 0
[days] => 0
[special_type] => 0
[special_amount] => 0
[have_weekday_relative] => 0
[have_special_relative] => 0
)
print_r($diff_n)
DateInterval Object
(
[y] => 0
[m] => 0
[d] => 0
[h] => 0
[i] => 0
[s] => 1
[f] => 0.41655
[weekday] => 0
[weekday_behavior] => 0
[first_last_day_of] => 0
[invert] => 0
[days] => 0
[special_type] => 0
[special_amount] => 0
[have_weekday_relative] => 0
[have_special_relative] => 0
)
d
DateTime Object
(
[date] => 2022-05-24 17:35:16.416318
[timezone_type] => 3
[timezone] => Europe/Helsinki
)
n
DateTime Object
(
[date] => 2022-05-24 17:35:16.000000
[timezone_type] => 1
[timezone] => +03:00
)
PHP 8 上的输出
上面的脚本位于 foo.php 中。也在 CentOS 7 服务器上运行。首先我显示 PHP 版本,然后运行脚本。这个输出对我来说看起来非常错误。
$ php --version
PHP 8.1.6 (cli) (built: May 11 2022 01:14:18) (NTS gcc x86_64)
Copyright (c) The PHP Group
Zend Engine v4.1.6, Copyright (c) Zend Technologies
$ php -f foo.php
$d->format("r"): Tue, 24 May 2022 17:35:05 +0300
print_r($diff_d)
DateInterval Object
(
[y] => 0
[m] => 0
[d] => 0
[h] => 0
[i] => 0
[s] => 1
[f] => 0.001302
[weekday] => 0
[weekday_behavior] => 0
[first_last_day_of] => 0
[invert] => 0
[days] => 0
[special_type] => 0
[special_amount] => 0
[have_weekday_relative] => 0
[have_special_relative] => 0
)
print_r($diff_n)
DateInterval Object
(
[y] => -1
[m] => 11
[d] => 29
[h] => 23
[i] => 0
[s] => 1
[f] => 0.363031
[weekday] => 0
[weekday_behavior] => 0
[first_last_day_of] => 0
[invert] => 0
[days] => 0
[special_type] => 0
[special_amount] => 0
[have_weekday_relative] => 0
[have_special_relative] => 0
)
d
DateTime Object
(
[date] => 2022-05-24 17:35:05.361724
[timezone_type] => 3
[timezone] => Europe/Helsinki
)
n
DateTime Object
(
[date] => 2022-05-24 17:35:05.000000
[timezone_type] => 1
[timezone] => +03:00
)
即使由于某种原因,要回溯一年然后再向前推进,那么不应该是 59 分钟,而不是零吗?
它似乎连接到从字符串创建的 DateTime 对象(因为将原始 DateTime 对象与现在进行比较就可以了)。但是,当我转储
$d
和 $n
时,唯一的区别是地理时区与数字偏移量以及缺少毫秒 - 但据我所知,它们代表彼此相同的瞬间(最多毫秒)。
有人可以解释为什么会发生这种情况,以便我知道我应该多么担心其余的代码吗?
此问题似乎已在最新的 PHP 版本 8.1.10 中得到修复:
我在 8.1.10 之前看到了这个关于 PHP 版本的错误,但我使用的是 PHP 版本 8.1.26