「PHPにおいてコンストラクタのアクセス権はpublic
である必要がある」とする記事をいくつか見かけたのですが、これは誤りです。
(例)https://laraweb.net/surrounding/1472/
他の言語のことは知りませんが、少なくともPHPは、コンストラクタをprivate
やprotected
に設定することができます。
コンストラクタが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);
}
}
余談
最近の技術系の記事は質の悪いものも多いので、特定のサイトの記述だけを見てそれを信じてしまうのは危険だと思います。
いろんなサイトから情報を得た上で、最後に公式ドキュメントを読むなど、多角的に情報を仕入れて勉強を進めることをおすすめします。