search
LoginSignup
0

posted at

updated at

時間を扱う、"Clock"

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的なメソッドもあったら便利だなと思いました。あ、独自で作れば良いのか)

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
What you can do with signing up
0