Singleton パターン

ログを出力しよう

APIの送受信やバッチ処理などの「やり取りがグラフィカルに見えづらい」処理を実装するにあたっては、ログを出力しておくのが定石です。

さっそく書いてみましょう。

class Logger
{
  private string $path;
  public function Logger()
  {
    $this->path = '/log/';
  }
  public function logging($message)
  {
    echo $this->path . 'にログメッセージ' . $message . "を書き出します.\n";
  }
}

$logger = new Logger();
$logger->logging('ログメッセージ');

しかし、ログを出力する際に、インスタンスを生成する必要はありません。
また、この例では軽量ですがインスタンス生成にコストの掛かるクラスの場合、ログを書き出す前に都度インスタンス生成をしていては非効率です。

そこで、唯一のインスタンスを生成させるようにします。

class Logger
{
  private static $instance = null;
  private static string $path;
  private function Logger()
  {
    self::$path = '/log/';
  }

  public function logging($message)
  {
    echo self::$path . 'にログメッセージ' . $message . "を書き出します.\n";
  }

  public static function getInctance()
  {
    if (self::$instance == null) {
      self::$instance = new Logger();
    }
    return self::$instance;
  }
}

$logger = Logger::getInctance();
$logger->logging('ログメッセージ');

ポイントは、コンストラクタをprivateにしていることと、自分自身のインスタンスをstaticにしていることです。

ログに限らず「生成のコストが高く、インスタンス変数を使わない(インスタンス化させる必要がない)」ようなクラスの場合、シングルトンパターンを検討すると良いでしょう。
ただし、スタティックな領域を利用するパターンなので、後ほどインスタンスとして扱ったり、継承などを利用して機能を拡張するのは難しいと思います。
そのためシングルトンパターンの導入は慎重に検討するべきであると思われます。

しかしシングルトンパターン自体、スクラッチ開発じゃない限り自分でシングルトンを実装することはさほど多くはないと思います。
まずはコードを読む際に「これはシングルトンだな」とその実装の意図を理解するくらいで良いと思います。