alex-patterson-webdev / date-time
PHP的DateTime工厂组件
Requires
- php: >=8.1
- psr/clock: ^1.0.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.6.0
- phpspec/prophecy: ^1.15.0
- phpstan/phpstan: ^1.4.8
- phpunit/phpunit: ^9.5
- squizlabs/php_codesniffer: ^3.6
Provides
This package is auto-updated.
Last update: 2024-09-11 04:02:55 UTC
README
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