在php应用程序的开发过程中,我们经常会遇到需要处理时间相关逻辑的场景。比如:
这些功能都离不开对“当前时间”的获取。然而,直接在代码中使用
new DateTimeImmutable()
time()
这些问题共同构成了一个开发者的噩梦:代码难以测试,功能难以验证,最终导致应用程序的健壮性下降。我们迫切需要一种方法来“控制”时间,尤其是在测试环境中,而不是被动地接受系统时钟的任意变化。
ergebnis/clock
幸运的是,PHP社区已经有了优雅的解决方案。
ergebnis/clock
ergebnis/clock
使用 Composer 安装
ergebnis/clock
立即学习“PHP免费学习笔记(深入)”;
<pre class="brush:php;toolbar:false;">composer require ergebnis/clock
ergebnis/clock
ergebnis/clock
Clock\Clock
now()
DateTimeImmutable
DateTimeImmutable
Clock\SystemClock
SystemClock
DateTimeZone
<pre class="brush:php;toolbar:false;"><?php
declare(strict_types=1);
use Ergebnis\Clock;
use DateTimeZone;
// 创建一个以上海时区为基准的系统时钟
$systemClock = new Clock\SystemClock(new DateTimeZone('Asia/Shanghai'));
// 获取当前上海时间
$currentTimeInShanghai = $systemClock->now();
echo $currentTimeInShanghai->format('Y-m-d H:i:s P');
// 输出示例:2023-10-27 15:30:00 +08:00 (取决于实际运行时间)Clock\UtcClock
UtcClock
SystemClock
<pre class="brush:php;toolbar:false;"><?php
declare(strict_types=1);
use Ergebnis\Clock;
// 创建一个UTC时钟
$utcClock = new Clock\UtcClock();
// 获取当前UTC时间
$currentTimeInUtc = $utcClock->now();
echo $currentTimeInUtc->format('Y-m-d H:i:s P');
// 输出示例:2023-10-27 07:30:00 +00:00Clock\FrozenClock
FrozenClock
ergebnis/clock
now()
DateTimeImmutable
<pre class="brush:php;toolbar:false;"><?php
declare(strict_types=1);
use Ergebnis\Clock;
use DateTimeImmutable;
// 创建一个固定在 2023年1月1日 10:00:00 的时钟
$fixedTime = new DateTimeImmutable('2023-01-01 10:00:00');
$frozenClock = new Clock\FrozenClock($fixedTime);
// 第一次获取时间
echo $frozenClock->now()->format('Y-m-d H:i:s') . "\n"; // 输出:2023-01-01 10:00:00
// 即使程序暂停一段时间,时间也不会改变
sleep(5);
// 第二次获取时间,仍然是固定的
echo $frozenClock->now()->format('Y-m-d H:i:s') . "\n"; // 输出:2023-01-01 10:00:00“冻结”现有时钟
SystemClock
UtcClock
freeze()
FrozenClock
<pre class="brush:php;toolbar:false;"><?php
declare(strict_types=1);
use Ergebnis\Clock;
use DateTimeZone;
$systemClock = new Clock\SystemClock(new DateTimeZone('Europe/Berlin'));
$frozenClock = $systemClock->freeze(); // 捕获当前柏林时间
// 从现在开始,$frozenClock 将始终返回被捕获的那个时间点
echo $frozenClock->now()->format('Y-m-d H:i:s P');ergebnis/clock
Clock\Clock
<pre class="brush:php;toolbar:false;"><?php
declare(strict_types=1);
use Ergebnis\Clock;
use DateTimeImmutable;
use DateTimeZone;
class SessionManager
{
private Clock\Clock $clock;
public function __construct(Clock\Clock $clock)
{
$this->clock = $clock;
}
public function isSessionExpired(DateTimeImmutable $sessionStartTime, int $durationInSeconds): bool
{
$expirationTime = $sessionStartTime->modify(sprintf('+%d seconds', $durationInSeconds));
return $this->clock->now() > $expirationTime;
}
}
// --- 在生产环境中 ---
$systemClock = new Clock\SystemClock(new DateTimeZone('Asia/Shanghai'));
$sessionManager = new SessionManager($systemClock);
// 假设会话开始于 10分钟前
$sessionStartTime = (new DateTimeImmutable('now', new DateTimeZone('Asia/Shanghai')))->modify('-10 minutes');
if ($sessionManager->isSessionExpired($sessionStartTime, 600)) { // 会话持续 10 分钟
echo "生产环境:会话已过期。\n"; // 如果当前时间恰好超过10分钟,则会输出
} else {
echo "生产环境:会话未过期。\n";
}
// --- 在测试环境中 ---
// 模拟一个固定的当前时间:2023-10-27 10:00:00
$fixedTestTime = new DateTimeImmutable('2023-10-27 10:00:00', new DateTimeZone('UTC'));
$frozenClock = new Clock\FrozenClock($fixedTestTime);
$testSessionManager = new SessionManager($frozenClock);
// 测试场景一:会话已过期
$testSessionStartTimeExpired = new DateTimeImmutable('2023-10-27 09:50:00', new DateTimeZone('UTC')); // 10分钟前
assert($testSessionManager->isSessionExpired($testSessionStartTimeExpired, 600) === true); // 10分钟后即10:00:00过期,所以此时已过期
echo "测试场景一:会话已过期,断言通过。\n";
// 测试场景二:会话未过期
$testSessionStartTimeNotExpired = new DateTimeImmutable('2023-10-27 09:55:00', new DateTimeZone('UTC')); // 5分钟前
assert($testSessionManager->isSessionExpired($testSessionStartTimeNotExpired, 600) === false); // 10分钟后即10:05:00过期,所以此时未过期
echo "测试场景二:会话未过期,断言通过。\n";通过这种方式,你的
SessionManager
ergebnis/clock
FrozenClock
SystemClock
如果你还在为PHP应用中时间依赖问题导致的测试难题和代码耦合而烦恼,那么
ergebnis/clock
以上就是如何优雅地解决PHP时间依赖问题:使用ergebnis/clock让你的测试更可控的详细内容,更多请关注php中文网其它相关文章!
PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号