0
0

More than 1 year has passed since last update.

時間を扱う、"Clock"

Last updated at Posted at 2022-12-22

Symfony Component Advent Calendar 2022の23日目の記事です。

最初に

SymfonyはPHPのフレームワークのひとつです。しかし、公式サイトの説明文には

Symfony is a set of PHP Components, a Web Application framework, a Philosophy, and a Community — all working together in harmony.
(SymfonyはPHPコンポーネントのセットで、Webアプリケーションフレームワークで、哲学、そしてコミュニティです。それらがハーモニーを奏でながら動作しています。)

と書かれている通り、PHPコンポーネントのセットで、たくさんのコンポーネントを提供しており、それらを組み合わせてひとつのフレームワークとして動作しています。Symfonyのコンポーネントは、Symfony上だけで動作するのではなく、他のPHPフレームワークやアプリケーションでも動作している強力なものが揃っています。

今回はそれらの中から、役立ちそうなもの・お薦めしたいものを紹介していきたいと思います。

※記事内ではautoloadのインポートは省略します。

時間を扱う、"Clock"

Clockは、時間を扱うコンポーネントです。Symfony 6.2から導入されました。

インストール

composer require symfony/clock

これはなに

Clock コンポーネントは、PSR-20: Clock拡張した、時間を扱うコンポーネントです。
PSR-20では、ClockInterfaceを実装したクラスを用意して、DateTimeImmutableを返すnow()を用意しようと定義されています。
SymfonyのClockコンポーネントは、PSR-20のClockInterfaceを拡張した、 独自のClockInterfaceを使って、PRS-20にない機能sleep(), withTimeZone()を実装しています。

PSR-20のClockInterface

ClockInterface.php

namespace Psr\Clock;

interface ClockInterface
{
    /**
     * Returns the current time as a DateTimeImmutable Object
     */
    public function now(): \DateTimeImmutable;

}

ClockコンポーネントのClockInterface

ClockInterface.php

namespace Symfony\Component\Clock;

use Psr\Clock\ClockInterface as PsrClockInterface;

interface ClockInterface extends PsrClockInterface
{
    public function sleep(float|int $seconds): void;

    public function withTimeZone(\DateTimeZone|string $timezone): static;
}

now()は現在時刻を返し、独自のsleep()は指定された時間スリープ、withTimezoneはタイムゾーンを変更したClockを返します。

現在時刻を返す

説明するほどでもないかもですが、now()は現在時刻をDateTimeImmutable返します。


use Symfony\Component\Clock\NativeClock;

$clock = new NativeClock();

// 現在時刻を返す
echo $clock->now()->format('Y-m-d h:i:s'); // 2022-12-23 07:00:00

 // 10秒スリープ
$clock->sleep(10);

// タイムゾーンを変える
$newClock = $clock->withTimeZone('Asia/Tokyo');

当然ながら、オートワイヤリング可能なので、色々な箇所で$now = new DateTimeImmutable()しなくてよくなります。

class SomeService
{
    public function __construct(private readonly ClockInterface $clock)
    {
    }
    
    publi function someMethod()
    {
        $item = new Item();
        $item
            ->setName('商品名')
            ->setPrice(1000)
            ->setCreatedAt($this->clock->now())
        ;
    }
}

3つのClock

ClockではClockInterfaceを実装した3つのClockを用意しており、それぞれの用途を定めています。

クラス 用途 備考
NativeClock 通常利用  now()を呼ぶごとにその瞬間の時刻を返す
MockClock テスト用 sleep()はスリープしない
now()は常に同じ時刻を返す
MonotonicClock パフォーマンス測定用 hrtime()を利用

NativeClockMockClocknow()の違いは、実際のコードを見てもらった方が早いです。NativeClockは常にメソッド呼び出し時にnewしていて、MockClockはプロパティのnowをクローンして返します。

NativeClock.php
    public function now(): \DateTimeImmutable
    {
        return new \DateTimeImmutable('now', $this->timezone);
    }
MockClock.php
    public function __construct(\DateTimeImmutable|string $now = 'now', \DateTimeZone|string $timezone = null)
    {
        if (\is_string($timezone)) {
            $timezone = new \DateTimeZone($timezone);
        }

        if (\is_string($now)) {
            $now = new \DateTimeImmutable($now, $timezone ?? new \DateTimeZone('UTC'));
        }

        $this->now = null !== $timezone ? $now->setTimezone($timezone) : $now;
    }

    public function now(): \DateTimeImmutable
    {
        return clone $this->now;
    }

まとめ

今回は、Clockを紹介しました。PSR準拠なものを使えるのは魅力的です。
(個人的にはFrozenTime的なメソッドもあったら便利だなと思いました。あ、独自で作れば良いのか)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0