1.0.0 2024-03-08 16:03 UTC

This package is not auto-updated.

Last update: 2024-09-27 12:37:29 UTC


README

创建日期时间对象的工厂。

Build Status Coverage Status Scrutinizer Code Quality

是什么

正如其名所示,这实际上就是一个时钟,用于指示当前的时间。

由于它产生 DateTime 对象,这个时钟在某种意义上也是特别的,因为它还可以读取日期。

Just a clock, really.

为什么

  • 一旦你在代码中使用“未经过滤”的日期时间对象,任何为其编写的测试都立即面临失败的风险,因为如果在 new DateTime 和你的断言之间存在一点时间差,测试就会失败。
  • 在客户端代码中实例化 new DateTimenew DateTimeImmutable 是一个静态调用。这引入了耦合并降低了可测试性。这显然对 date_create() 等类似函数来说也是一样。
  • 从时钟获取时间比每次想知道时间有多晚时都实例化一个新的瞬间要自然得多。

安装

使用 composer require stratadox/clock 安装

示例

时钟示例

在一个需要知道时间的服务中

<?php
namespace Your\Project;

use Stratadox\Clock\Clock;

class SomeFactory
{
    private $clock;

    public function __construct(Clock $clock)
    {
        $this->clock = $clock;
    }

    public function createSomething(): Something
    {
        return new Something($this->clock->now());
    }
}

class Something
{
    private $creationDate;

    public function __construct(\DateTimeInterface $creationDate)
    {
        $this->creationDate = $creationDate;
    }

    public function creationDate(): \DateTimeInterface
    {
        return $this->creationDate;
    }
}

可倒退时钟示例

在一个需要倒退或快进时钟的服务中

<?php
namespace Your\Project;

use Stratadox\Clock\RewindableClock;

class Scheduler
{
    private $clock;

    public function __construct(RewindableClock $clock)
    {
        $this->clock = $clock;
    }

    public function scheduleForTheNextThreeHours(): Schedule
    {
        return new Schedule(
            new Activity($this->clock->now()),
            new Activity($this->clock->fastForward(new \DateInterval('PT1H'))->now()),
            new Activity($this->clock->fastForward(new \DateInterval('PT2H'))->now())
        );
    }

    public function whenDoIWantThisOnMyDesk(): \DateTimeInterface
    {
        return $this->clock->rewind(new \DateInterval('P1D'))->now();
    }
}

选择时钟

默认实现是 DateTimeClock。每次调用 now 时,它都会产生一个新的 DateTimeImmutable 对象。

如果日期时间对象需要传递给一个具有 DateTime 类型提示的东西,或者依赖于可变日期时间对象,则最好解决该问题。例如,通过将 DateTime 提示替换为 DateTimeIterfaceDateTimeImmutable,或者传递一个 RewindableClock。在那种情况下不可用的情况下,可以使用 DateTimeMutableClock 时钟。

如果上下文中时间区很重要,还有一个 TimeZoneAwareClock,它将时间区作为构造函数参数。

为了防止在运行其他代码时时钟在滴答作响,你的测试可以实例化并注入一个 UnmovingClock

在服务定义中

<?php
use Stratadox\Clock\Clock;
use Stratadox\Clock\DateTimeClock;

$container->set(Clock::class, function () {
    return DateTimeClock::create();
});

在单元测试中

<?php
use Your\Project\SomeFactory;
use PHPUnit\Framework\TestCase;
use Stratadox\Clock\UnmovingClock;

class SomethingTest extends TestCase
{
    public function testCreatingSomething(): void
    {
        $testTime = new DateTimeImmutable('1-1-1960');
        $factory = new SomeFactory(
            UnmovingClock::standingStillAt($testTime)
        );

        $something = $factory->createSomething();

        $this->assertEquals($testTime, $something->creationDate());
    }
}

当需要能够倒退或快进时钟时,使用 RewindableDateTimeClock 实现。

在服务定义中

<?php
use Stratadox\Clock\RewindableClock;
use Stratadox\Clock\RewindableDateTimeClock;

$container->set(RewindableClock::class, function () {
    return RewindableDateTimeClock::create();
});

在单元测试中

<?php
use Your\Project\Scheduler;
use PHPUnit\Framework\TestCase;
use Stratadox\Clock\RewindableDateTimeClock;
use Stratadox\Clock\UnmovingClock;

class SchedulerTest extends TestCase
{
    public function testWhenItShouldBeOnTheirDesk(): void
    {
        $scheduler = new Scheduler(
            RewindableDateTimeClock::using(UnmovingClock::standingStillAt(
                new DateTimeImmutable('16-5-1991')
            ))
        );

        $this->assertEquals(
            new DateTimeImmutable('15-5-1991'),
            $scheduler->whenDoIWantThisOnMyDesk()
        );
    }
}

以下是何时使用哪种时钟的概述

时钟何时使用
DateTimeClock在大多数情况下
DateTimeMutableClock当你不能使用 DateTimeImmutable 时
TimeZoneAwareClock当默认时区不够用时
TimeZoneAwareMutableClock当上述两个原因都适用时
UnmovingClock在测试期间
RewindableDateTimeClock如果需要将时钟设置回或前进

请注意,可倒退时钟可以与任何其他时钟结合使用,例如,在特定时区产生倒退的可变日期时间对象。