Menu

PHPのコンストラクタ:__constructとプロパティの昇格

PHPのコンストラクタは__construct()メソッドで、new ClassName(...)と書くと自動的に実行されます。コンストラクタでのプロパティの昇格、デフォルト引数と名前付き引数、検証、parent::__construct()、静的ファクトリーメソッドで複数のコンストラクタを実現する方法を学びます。

このページのコードはエディタで実行できます - 編集してすぐに結果を確認できます。

PHPのコンストラクタは__construct()という名前のメソッドです。new ClassName(...)と書くとPHPが自動で呼び出し、括弧の中の引数がその引数になるので、オブジェクトは値がすでに設定された状態で作られます。

コンストラクタがなければ、空のオブジェクトを作ってから各プロパティを設定することになり、1つ設定し忘れても何も止めてくれません。コンストラクタがあれば、引数なしのnew User()はArgumentCountErrorになります。

コンストラクタでのプロパティの昇格

プロパティを宣言し、引数として並べ、$this->name = $nameと代入すると、各名前を3回繰り返すことになります。PHP 8.0以降は、コンストラクタの引数の前にアクセス修飾子を付けると、その3つを一度に行えます。

昇格した引数はreadonlyにもでき(public readonly string $id)、不変の値オブジェクトをいちばん短く書く方法です。昇格した引数と普通の引数は混ぜられ、コンストラクタの本体には、昇格したプロパティが代入されたあとに実行されるコードも書けます。

デフォルト値と名前付き引数

コンストラクタの引数は、ほかの関数と同じようにデフォルト値を持てます。デフォルト値付きの引数は必須の引数のあとに置きます。名前付き引数(PHP 8.0)を使えば、呼び出し側は前にあるデフォルト値をすべて繰り返さずに、欲しいオプションまで飛ばせます。

実行してください。出力にはHTMLが含まれるので、Pageタブには描画された3つのボタンが、OutputタブにはPHPが出力したタグが表示されます。(new Button('Save'))->render()の括弧に注目してください。PHP 8.4以降は省略できますが、PHP 8.3では必要です。

コンストラクタで引数を検証する

コンストラクタはfalseやエラーコードを返せません。返したものは無視されるからです。不正な入力を拒否するには例外を投げます。そうすればオブジェクトは作られないので、プログラムのほかの部分は受け取るTemperatureをすべて信頼できます。

これらの例外のキャッチについては、try catchのページで詳しく扱っています。

静的ファクトリーメソッドで複数のコンストラクタ

PHPにはコンストラクタのオーバーロードがなく、1つのクラスに__constructは1つです。オブジェクトを別々の入力(日付の文字列、配列、タイムスタンプ)から作れるようにするには、引数を準備してnew static(...)を呼ぶ名前付きの静的メソッドを追加します。コンストラクタをprivateにすれば、全員がファクトリーを通すよう強制できます。

これでクラスの外からnew Color(1, 2, 3)とするとError(「Call to private Color::__construct() from global scope」)が投げられます。ここでnew selfではなくnew staticを使う理由はstaticのページで説明しています。

parent::__constructで親のコンストラクタを呼ぶ

子クラスが自分のコンストラクタを定義すると、親のコンストラクタは自動では実行されません。子が自分のプロパティを加える前に親のプロパティが設定されるよう、parent::__construct(...)を(たいてい最初に)呼びます。

子にコンストラクタがまったくなければPHPは親のものを使うので、new Truck('Volvo')は引数をそのままVehicle::__constructに渡します。詳しくは継承を参照してください。

parent::__constructの書き忘れ

このミスは、起きた行ではエラーになりません。子のコンストラクタは実行され、親の型付きプロパティは未初期化のまま残り、最初に読まれたところであとからプログラムが失敗します。

Post::__constructの最初の行にparent::__construct();を加えてもう一度実行すると、日付が表示されます。関連するメソッドの__destruct()は、オブジェクトへの最後の参照がなくなったときかスクリプトが終わるときに実行されます。PHPは各リクエストの終わりに自分でファイルを閉じてメモリを解放するので、日常的なコードで必要になることはまれです。

よくある質問

PHPの__constructとは何ですか?

__construct()はコンストラクタで、newでオブジェクトが作られた直後にPHPが自動で呼ぶメソッドです。new User('Ada', 36)に渡した引数は__construct(string $name, int $age)に渡され、たいていプロパティに格納されます。

PHPのコンストラクタでのプロパティの昇格とは何ですか?

PHP 8.0以降、コンストラクタの引数にアクセス修飾子を付けると、プロパティの宣言と代入が1ステップで行われます:public function __construct(private string $name) {}は、private string $name;を宣言して本体に$this->name = $name;と書くのと同じです。

PHPのクラスは複数のコンストラクタを持てますか?

持てません。PHPにはメソッドのオーバーロードがないので、クラスの__constructは1つです。デフォルト値付きの任意の引数を使うか、正しい引数でnew static(...)を呼ぶpublic static function fromArray(array $data): staticのような静的ファクトリーメソッドを追加します。

PHPでは親のコンストラクタは自動で呼ばれますか?

子クラスが自分のコンストラクタを持たない場合だけです。子が__constructを定義していれば、自分でparent::__construct(...)を(たいてい最初の行で)呼ばない限り、親のコンストラクタは実行されません。

PHPのコンストラクタは値を返せますか?

返せません。newは常にオブジェクトを返し、__constructが返したものは無視されます。問題を知らせるには、コンストラクタから例外を投げます。たとえばthrow new InvalidArgumentException('Age must be positive')です。

Coddyのプログラミング言語のイラスト

Coddyでコードを学ぼう

始める