LoginSignup
13
7

More than 3 years have passed since last update.

PHPのコンストラクタはprivateにできる

Posted at

「PHPにおいてコンストラクタのアクセス権はpublicである必要がある」とする記事をいくつか見かけたのですが、これは誤りです。
(例)https://laraweb.net/surrounding/1472/

他の言語のことは知りませんが、少なくともPHPは、コンストラクタprivateprotectedに設定することができます。

コンストラクタがprivateになるとどうなるか

クラスの外からnewできなくなります。
以下のコードはFatalエラーになります。

<?php
class Hoge {
    private function __construct(){}
}

// Fatal error: Uncaught Error: Call to private Hoge::__construct() from invalid context
$hoge2 = new Hoge();

自分のクラスの中であればnewできます。
以下のコードは正常に動作します。

<?php
class Hoge {
    private function __construct(){}

    public static function instance() : self
    {
        return new self();
    }
}

// OK(public な静的メソッドを通しているのでインスタンスを取得できる)
$hoge = Hoge::instance();
echo get_class($hoge); // -> Hoge

protectedにした場合は、自分自身とそれを継承したクラスからのみnewが可能になります。

いつprivateにするのか

外からインスタンス化できないんじゃ使い道が無いようにも思えますが、案外そんなことはありません。

例えば以下のような使い方が考えられます。(※設計上良くない!ってパターンもあるかもしれませんが、今回は多めに見てください<(_ _)>)

定数や静的な要素のみを定義したクラス

定数やstaticな要素のみを定義したクラスは、インスタンス化する意味が無いので、privateなコンストラクタを定義することで、誤ってnewしようとしているおかしなコードを未然に防ぐことができます。

class State
{
    const SUCCESS = 1;
    const FAILURE = 0;

    private function __construct();
}

実行中に1つだけ生成したいクラス(シングルトンパターン)

実行時に生成されるのが1つまでにしたいようなクラスは、コンストラクタをprivateにしておき、インスタンス取得用の静的メソッドを作っておきます。
最初に呼ばれたときに生成したインスタンスを静的なprivateプロパティとして保持しておき、2回目以降はそれを返すことで、インスタンス取得用のメソッドが何度呼ばれても、生成されるインスタンスが1つである状態を作ることができます。外からnewできないので、それが保証されるわけです。

<?php

class GlobalTime
{
    private static $instance = null;

    private function __construct(){}

    // ...

    public static function instance()
    {
        if (is_null(self::$instance)) {
            self::$instance = new self();
        }

        return self::$instance;
    }
}

インスタンス生成に特定のメソッドを使わせたい場合

インスタンス生成にnewではなく、別のファクトリメソッドを使わせることで、コードが説明的になったり、柔軟なインスタンス運用(キャッシュさせておくとか)ができる場合があります。
その場合も、インスタンス化の手段を絞る意味でコンストラクタをprivateにしておくことが有効となります。

class Price
{
    private $value;

    private function __construct(int $value)
    {
        $this->value = $value;
    }

    // ...

    public static function valueOf(int $value)
    {
        return new self($value);
    }
}

余談

最近の技術系の記事は質の悪いものも多いので、特定のサイトの記述だけを見てそれを信じてしまうのは危険だと思います。
いろんなサイトから情報を得た上で、最後に公式ドキュメントを読むなど、多角的に情報を仕入れて勉強を進めることをおすすめします。

13
7
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
13
7