はじめに
オブジェクト指向プログラミングにおいて、「オブジェクトが生成されるタイミングで、初期化のための処理を自動的に実行したい」という場面は非常によくあります。PHPでこの役割を担うのが __construct() という特別なメソッド(マジックメソッド)です。
__construct() は、new ClassName() によってオブジェクトが生成される際に自動的に呼び出される、PHPのオブジェクト指向機能の中でも最も基本的かつ重要な仕組みの一つです。プロパティの初期化、依存オブジェクトの注入、必須パラメータの検証など、オブジェクトが正しい状態で誕生することを保証するために欠かせません。本記事では、その基本的な使い方から、コンストラクタプロパティプロモーションのようなモダンな書き方、継承時の注意点まで、実践的なコード例とともに詳しく解説します。
メソッド概要
| 項目 | 内容 |
|---|---|
| メソッド名 | __construct() |
| 種別 | マジックメソッド(PHPが特別扱いする命名規則のメソッド) |
| シグネチャ | public function __construct(...$args) |
| 呼び出しタイミング | new ClassName(...) によるオブジェクト生成時に自動的に呼び出される |
| 戻り値 | なし(値を返すことができない) |
| 対応バージョン | PHP 4以降(PHP 5で現在の統一された命名規則になった) |
| 対になるメソッド | __destruct()(オブジェクト破棄時に呼ばれる) |
| 特徴的な機能 | コンストラクタプロパティプロモーション(PHP 8.0以降) |
オブジェクト生成の流れ(イメージ図)
new User('太郎', 30)
│
▼
┌───────────────────────┐
│ 1. メモリ上に空のオブジェクトを確保 │
│ 2. __construct('太郎', 30) を自動呼び出し │
│ ここで渡した引数がそのまま │
│ コンストラクタの引数になる │
└───────────┬───────────┘
▼
class User {
public function __construct(
public string $name,
public int $age
) {
// ここでプロパティの初期化や検証を行う
}
}
│
▼
完全に初期化された$userオブジェクトが返る
ポイントは、__construct() が**new キーワードによって暗黙的に呼び出される**という点です。開発者が明示的に $obj->__construct() と呼び出すことは通常なく(呼び出すこと自体は可能ですが、意図しない再初期化を招くため避けるべきです)、オブジェクト生成の瞬間に必ず1回だけ実行される、いわば「誕生の儀式」のような役割を担っています。
実践サンプル7選
例1:基本的な使い方
<?php
class BasicUser
{
public string $name;
public int $age;
public function __construct(string $name, int $age)
{
// コンストラクタ内でプロパティを初期化する
$this->name = $name;
$this->age = $age;
}
}
$user = new BasicUser('太郎', 30);
echo "{$user->name}さん({$user->age}歳)" . PHP_EOL;
例2:コンストラクタプロパティプロモーションによる簡潔な記述(PHP 8.0以降)
<?php
class PromotedUser
{
/**
* PHP 8.0以降では、引数にアクセス修飾子を付けるだけで
* プロパティの宣言と代入が自動的に行われる
*/
public function __construct(
public string $name,
public int $age,
private string $email = ''
) {
}
public function getEmail(): string
{
return $this->email;
}
}
$user = new PromotedUser('花子', 25, 'hanako@example.com');
echo "{$user->name}: {$user->getEmail()}" . PHP_EOL;
例3:必須パラメータの検証を行うクラス
<?php
class ValidatedProduct
{
public function __construct(
public readonly string $name,
public readonly float $price
) {
// コンストラクタ内で不正な値を検出し、早期に例外をスローする
if ($price < 0) {
throw new InvalidArgumentException('価格は0以上である必要があります');
}
if (trim($name) === '') {
throw new InvalidArgumentException('商品名は必須です');
}
}
}
try {
$product = new ValidatedProduct('ノート', -100);
} catch (InvalidArgumentException $e) {
echo 'エラー: ' . $e->getMessage() . PHP_EOL;
}
例4:依存オブジェクトを注入するクラス(依存性注入)
<?php
interface LoggerInterface
{
public function log(string $message): void;
}
class FileLogger implements LoggerInterface
{
public function log(string $message): void
{
echo "[LOG] {$message}" . PHP_EOL;
}
}
class OrderProcessor
{
/**
* コンストラクタで依存オブジェクトを受け取ることで、
* クラスが必要とする協力オブジェクトを明示的に保証する
*/
public function __construct(private LoggerInterface $logger)
{
}
public function process(string $orderId): void
{
$this->logger->log("注文 {$orderId} を処理しました");
}
}
$processor = new OrderProcessor(new FileLogger());
$processor->process('ORDER-001');
例5:継承関係における親クラスのコンストラクタ呼び出し
<?php
class Animal
{
public function __construct(protected string $name)
{
}
}
class Dog extends Animal
{
/**
* 子クラスで__construct()をオーバーライドする場合、
* 親クラスの初期化処理を引き継ぐにはparent::__construct()を
* 明示的に呼び出す必要がある
*/
public function __construct(string $name, private string $breed)
{
parent::__construct($name);
}
public function describe(): string
{
return "{$this->name}({$this->breed})";
}
}
$dog = new Dog('ポチ', '柴犬');
echo $dog->describe() . PHP_EOL;
例6:デフォルト値とnull許容型を組み合わせた柔軟な初期化
<?php
class Configuration
{
private array $options;
/**
* デフォルト値を持つ引数を活用し、
* 一部のパラメータだけを指定した生成を可能にする
*/
public function __construct(
private string $environment = 'production',
?array $options = null
) {
$this->options = $options ?? ['debug' => false, 'cache' => true];
}
public function describe(): string
{
return "{$this->environment}: " . json_encode($this->options);
}
}
$default = new Configuration();
$custom = new Configuration('development', ['debug' => true]);
echo $default->describe() . PHP_EOL;
echo $custom->describe() . PHP_EOL;
例7:staticファクトリーメソッドと組み合わせて生成方法を制限する
<?php
class Money
{
/**
* コンストラクタをprivateにすることで、
* new Money(...)による直接生成を禁止し、
* 用途に応じたファクトリーメソッド経由の生成を強制する
*/
private function __construct(
public readonly int $amountInCents,
public readonly string $currency
) {
}
public static function fromYen(int $yen): self
{
return new self($yen * 100, 'JPY');
}
public static function fromDollars(float $dollars): self
{
return new self((int) round($dollars * 100), 'USD');
}
}
$yenAmount = Money::fromYen(1500);
echo "{$yenAmount->amountInCents} {$yenAmount->currency}" . PHP_EOL;
// new Money(...) は直接呼び出せない(privateのため)
関連機能との比較
| 機能 | 役割 | __construct()との違い |
|---|---|---|
__construct() | オブジェクト生成時に自動実行される初期化処理 | 本記事の対象。newによって暗黙的に呼ばれる |
__destruct() | オブジェクト破棄時に自動実行される終了処理 | __construct()とは逆に、オブジェクトのライフサイクルの終わりを扱う |
__invoke() | オブジェクトを関数のように呼び出した際に実行される | オブジェクト生成後の呼び出しに関するマジックメソッドで、目的が異なる |
| staticファクトリーメソッド | 名前付きの生成方法を提供する | __construct()自体を隠蔽・制限しつつ、複数の生成パターンを提供できる |
| コンストラクタプロパティプロモーション | 引数宣言とプロパティ代入を統合する記法 | __construct()の中身を簡潔に書くための、PHP 8.0以降の構文的な仕組み |
よくある落とし穴(注意点)
- 戻り値を返すことができない
__construct()はいかなる値もreturnすることができません(return;のように値なしで早期リターンすることは可能です)。初期化の結果を呼び出し元に伝えたい場合は、プロパティやメソッドを通じてアクセスする設計にする必要があります。 - 継承時に
parent::__construct()の呼び出しを忘れる 子クラスで__construct()をオーバーライドすると、親クラスの__construct()は自動的には呼び出されません。親クラスの初期化処理も引き継ぎたい場合は、明示的にparent::__construct()を呼び出す必要があります(例5を参照)。 - コンストラクタ内で重い処理や失敗しうる処理を行いすぎる データベース接続やファイルI/Oのような、失敗する可能性のある重い処理をコンストラクタ内に詰め込みすぎると、オブジェクト生成そのものが不安定になりがちです。可能であれば、こうした処理は専用のメソッドや初期化フェーズに分離することを検討しましょう。
- プロパティプロモーションとデフォルト値のあるプロパティ宣言を重複させる コンストラクタプロパティプロモーション(例2)を使う場合、クラス本体で同名のプロパティを別途宣言する必要はありません。両方を書いてしまうと構文エラーになります。
__construct()を明示的に呼び出してオブジェクトを再初期化しようとする$obj->__construct(...)のように直接呼び出すこと自体は文法上可能ですが、これは通常のオブジェクトのライフサイクルを想定していない使い方であり、意図しない状態の変化を招く可能性があります。再初期化が必要な設計は、専用のメソッドを用意する方が安全です。
まとめ
| 観点 | まとめ |
|---|---|
| 何をするメソッドか | newによるオブジェクト生成時に自動的に呼び出される、初期化用のマジックメソッド |
| 主な用途 | プロパティの初期化、必須パラメータの検証、依存オブジェクトの注入 |
| モダンな書き方 | PHP 8.0以降のコンストラクタプロパティプロモーションで記述を簡潔化できる |
| 継承時の注意 | オーバーライド時はparent::__construct()の呼び出しが必要な場合がある |
| 注意点 | 戻り値を返せないこと、重い処理を詰め込みすぎないこと、再初期化目的での直接呼び出しを避けること |
__construct() は、PHPのオブジェクト指向プログラミングにおいて、オブジェクトが常に正しい状態で生成されることを保証するための中心的な仕組みです。コンストラクタプロパティプロモーションのようなモダンな構文と組み合わせることで、簡潔かつ堅牢なクラス設計を実現できます。
