PHP的DateTime工厂组件

0.6.1 2023-04-11 00:55 UTC

This package is auto-updated.

Last update: 2024-09-11 04:02:55 UTC


README

build codecov Scrutinizer Code Quality

Arp\DateTime

关于

该库提供了PSR-20 Clock ClockInterface的实现以及一些工厂类,这些工厂类抽象了PHP原生日时间对象的创建。

安装

通过composer安装。

require alex-patterson-webdev/date-time ^0.6

理论

通过在简单接口集合后抽象日期时间的创建,我们可以让开发者将日期时间创建视为一种服务。可以使用Arp\DateTime\DateTimeFactory作为任何通常需要使用new \DateTime()的代码的替代。

考虑一个示例方法UserService::updateLastLoginDate();该方法是用来更新用户的最后登录日期为当前日期和时间。

class UserService
{
    public function updateLastLoginDate($user)
    {
        $user->setLastLoginDate(new \DateTime());
    }
}

虽然这个方法简单,但在单元测试中很难断言'当前时间'的值。作为替代,我们可以将此示例更新为包含DateTimeFactory,这将抽象\DateTime对象的创建。

class UserService
{
    private DateTimeFactoryInterface $dateTimeFactory;

    public function __construct(DateTimeFactoryInterface $dateTimeFactory)
    {
        $this->dateTimeFactory = $dateTimeFactory;
    }

    public function updateLastLoginDate($user)
    {
        $user->setLastLoginDate($this->dateTimeFactory->createDateTime());
    }
}

这种方法有几个显著的优点

  • DateTimeFactoryInterface为所有\DateTime对象创建提供了一个抽象。
  • 由于现在可以模拟$this->dateTimeFactory->createDateTime()的返回值,单元测试和断言日期时间值变得非常容易。
  • 当无法创建日期对象时,而不是返回布尔值false,工厂类将抛出DateTimeException

DateTimeFactoryInterface

DateTimeFactoryInterface公开了两个公共方法,createDateTime()createFromFormat()。方法签名与PHP \DateTime方法相似。

interface DateTimeFactoryInterface
{
    /**
     * @throws DateTimeFactoryException
     */
    public function createDateTime(?string $spec = null, $timeZone = null): \DateTimeInterface;

    /**
     * @throws DateTimeFactoryException
     */
    public function createFromFormat(string $format, string $spec, $timeZone = null): \DateTimeInterface;
}

createDateTime()方法可以替代\DateTime::__construct的使用。而createFromFormat()方法可以替代\DateTime::createFromFormat()的使用。

然而,有一些差异需要考虑。

  • 接口中的方法被定义为非静态的,并且需要工厂实例来调用。
  • 如果无法创建\DateTime实例,将抛出DateTimeFactoryException
  • createDateTime()方法的$spec参数可以接受null。传递null相当于使用当前日期和时间,即now
  • $timeZone可以是字符串或\DateTimeZone实例。如果提供了一个受支持的DateTimeZone字符串,内部将创建\DateTimeZone实例;否则将抛出DateTimeFactoryException

实现

该软件包提供了两个默认的DateTimeFactoryInterface实现。

  • DateTimeFactory可以用来创建\DateTime实例。
  • DateTimeImmutableFactory可以用来创建\DateTimeImmutible实例

由于这两个类都实现了DateTimeFactoryInterface,因此它们可以以相同的方式使用。

$dateTimeFactory = new \Arp\DateTime\DateTimeFactory();
$dateTimeImmutableFactory = new \Arp\DateTime\DateTimeImmutableFactory();

try {
    /** @var \DateTime $dateTime **/
    $dateTime = $dateTimeFactory->createDateTime();

    /** @var \DateTimeImmutable $dateTimeImmutable **/
    $dateTimeImmutable = $dateTimeImmutableFactory->createDateTime();
} catch (\DateTimeFactoryException $e) {
    // if the date creation fails
}

DateTimeZoneFactory

可以使用任何实现了Arp\DateTime\DateTimeZoneFactoryInterface的类来创建\DateTimeZone实例。

/*
 * @throws DateTimeZoneFactoryException
 */
public function createDateTimeZone(string $spec): \DateTimeZone;

接口的默认实现是 Arp\DateTime\DateTimeZoneFactory

$dateTimeZoneFactory = new \Arp\DateTime\DateTimeZoneFactory();

try { 
    /** @var \DateTimeZone $dateTimeZone **/
    $dateTimeZone = $dateTimeZoneFactory->createDateTimeZone('UTC');
} catch (\DateTimeZoneFactoryException $e) {
    // The \DateTimeZone() could not be created
}

PSR-20 时钟接口

使用PSR标准通过创建一种访问当前时间的方式,为实施项目提供与其他包之间的互操作性。

该包提供了一系列PSR-20 时钟接口的实现。

  • Arp\DateTime\Psr\Clock 是一个默认实现,可以提供所需的DateTimeZone。
  • Arp\DateTime\Psr\SystemClock 是一个实现PSR\Clock\ClockInterface的实例,它将始终使用配置的系统时区提供当前时间。
  • Arp\DateTime\Psr\FixedClock 是一个实现PSR\Clock\ClockInterface的实例,它将始终返回一个固定的\DateTimeImmutable;这在测试中可能很有用。

示例用法

use Arp\DateTime\DateTimeImmutableFactory;
use Arp\DateTime\Psr\SystemClock;

// Fetch the current time using the UTC timezone
$clock = new Clock(new DateTimeImmutableFactory(), 'UTC');
$utcTime = $clock->now();

// Fetch the current time using the systems configured timezone
$clock = new SystemClock(new DateTimeImmutableFactory());
$systemTime = $clock->now();

// Calls to FixedClock::now() will always return the same time provided in the constructor 
$clock = new FixedClock(new \DateTimeImmutable());
$fixedTime = $clock->now();

单元测试

可以通过从应用程序根目录使用PHPUnit执行单元测试。

php vendor/bin/phpunit