| この記事の要点 |
|
基本
class User
{
public string $name;
public int $age;
public function __construct(string $name, int $age = 0)
{
$this->name = $name;
$this->age = $age;
}
}
$u = new User('田中', 30);
echo $u->name; // 田中
$u2 = new User('鈴木'); // 既定値を使う
$u3 = new User(age: 25, name: '佐藤'); // 名前付き引数(PHP 8 以降)
PHP 4 時代の「クラス名と同じ名前のメソッド」は PHP 8 で削除されました。__construct 以外はただのメソッドとして扱われます。
コンストラクタプロパティ昇格(PHP 8)
// 従来: 同じ名前を 3 回書く
class User
{
private string $name;
public function __construct(string $name) { $this->name = $name; }
}
// PHP 8: 引数に可視性を書くだけでプロパティになる
class User
{
public function __construct(
private string $name,
private int $age = 0,
) {}
}
// readonly を付ければ生成後に変更できない(PHP 8.1 以降)
class Point
{
public function __construct(
public readonly int $x,
public readonly int $y,
) {}
}
$p = new Point(1, 2);
echo $p->x; // 1
// $p->x = 5; // Error: Cannot modify readonly property Point::$x
値を保持するだけのクラスは、この書き方で数行に収まります。値オブジェクトには readonly を付けて、あとから壊されないようにしておくと安全です。
オーバーロードはできない
class Point
{
public function __construct(int $x, int $y) {}
public function __construct(string $text) {} // Fatal error: Cannot redeclare Point::__construct()
}
方法 1: 既定値と可変長引数
class Point
{
public function __construct(
public readonly int $x = 0,
public readonly int $y = 0,
) {}
}
new Point(); // (0, 0)
new Point(1); // (1, 0)
new Point(y: 5); // (0, 5)
方法 2: static のファクトリメソッド(推奨)
class Point
{
private function __construct(
public readonly int $x,
public readonly int $y,
) {}
public static function of(int $x, int $y): static
{
return new static($x, $y);
}
public static function fromText(string $text): static
{
[$x, $y] = array_map('intval', explode(',', $text));
return new static($x, $y);
}
public static function origin(): static
{
return new static(0, 0);
}
}
$a = Point::of(1, 2);
$b = Point::fromText('3,4');
$c = Point::origin();
作り方ごとに名前が付くので、呼び出し側を読むだけで意図が分かります。__construct を private にすれば、他の作り方を封じられます。
継承したときは parent を呼ぶ
class Base
{
public function __construct(protected string $name) {}
}
class Admin extends Base
{
public function __construct(string $name, private int $level)
{
parent::__construct($name); // ← これを書かないと $name が設定されない
}
}
class Broken extends Base
{
public function __construct(private int $level) {} // parent を呼び忘れ
}
$b = new Broken(3);
// $b->name にアクセスすると
// Error: Typed property Base::$name must not be accessed before initialization
子クラスで __construct を定義しなければ親のものがそのまま使われます。定義した瞬間に親の初期化は行われなくなるため、呼び忘れが最頻出のバグです。
デストラクタ
class FileHandle
{
private $fp;
public function __construct(string $path)
{
$this->fp = fopen($path, 'r');
}
public function __destruct()
{
if (is_resource($this->fp)) {
fclose($this->fp);
}
}
}
$h = new FileHandle('data.txt');
unset($h); // 参照が 0 になった時点で __destruct が呼ばれる
__destruct は参照がすべて無くなったときか、スクリプト終了時に呼ばれます。ただし呼ばれる順序は保証されず、循環参照があると遅れます。確実に閉じたい資源は、明示的な close() メソッドを用意してください。
コンストラクタに書かないほうがよいこと
// 悪い例: 生成しただけで通信・DB 接続が走る
class ReportService
{
private array $rates;
public function __construct()
{
$this->rates = (new TaxApi())->fetchAll(); // テストで差し替えられない
}
}
// 良い例: 必要なものを受け取るだけ
class ReportService
{
public function __construct(private TaxRateProvider $rates) {}
public function build(): string
{
return $this->rates->get('JP'); // 実際に使うときに呼ぶ
}
}
| コンストラクタで | やること |
|---|---|
| やってよい | 引数の代入、値の検証、既定値の設定 |
| 避ける | DB 接続・HTTP 通信・ファイル読み込み・重い計算 |
| 避ける | $this を外部に渡す(初期化途中の状態が漏れる) |
値の検証を入れる
class Age
{
public function __construct(public readonly int $value)
{
if ($value < 0 || $value > 150) {
throw new InvalidArgumentException("年齢が範囲外です: {$value}");
}
}
}
new Age(30); // OK
new Age(-1); // InvalidArgumentException
コンストラクタで検証すると、そのクラスのインスタンスは常に正しい値を持つと保証できます。以降の処理で毎回チェックする必要がなくなります。
複製したときの挙動(__clone)
class Order
{
public function __construct(
public string $code,
public Address $address,
) {}
}
$a = new Order('A-1', new Address('東京'));
$b = clone $a;
$b->address->city = '大阪';
echo $a->address->city; // 大阪 ← 中のオブジェクトは共有されたまま
clone は浅いコピーです。プロパティに入っているオブジェクトは同じ実体を指し続けます。中身まで複製したいときは __clone() を書きます。
class Order
{
public function __construct(
public string $code,
public Address $address,
) {}
public function __clone(): void
{
$this->address = clone $this->address; // 中のオブジェクトも複製する
}
}
$b = clone $a;
$b->address->city = '大阪';
echo $a->address->city; // 東京 影響しない
readonly プロパティは PHP 8.3 から __clone() の中でだけ再代入できるようになりました。値オブジェクトの「一部だけ変えた新しいインスタンス」を作るときに使えます。
初期化されていないプロパティ
class User
{
public string $name; // 型付きで既定値なし → 未初期化状態がある
public function __construct() {} // $name に入れていない
}
$u = new User();
echo $u->name;
// Error: Typed property User::$name must not be accessed before initialization
var_dump(isset($u->name)); // false 未初期化は isset で false になる
型付きプロパティは null ではなく「未初期化」という状態を持ちます。null を許すなら ?string $name = null; と書き、そうでなければコンストラクタで必ず値を入れてください。
作れないときは例外を投げる
class Config
{
private array $values;
public function __construct(string $path)
{
if (!is_file($path)) {
throw new RuntimeException("設定ファイルがありません: {$path}");
}
$this->values = require $path;
}
}
try {
$c = new Config('/no/such/file.php');
} catch (RuntimeException $e) {
echo $e->getMessage();
}
「作れたのに中身が正しくない」インスタンスを返さないのが原則です。失敗したら例外を投げて、生成そのものを失敗させます。null を返したくなったら、それは static のファクトリメソッド(tryFrom() のような名前)で表現してください。
関連
- 文法 — 親カテゴリ
- クラスとインスタンス
- static関数 — ファクトリメソッド
- 継承の構文
- カプセル化の具体例
- 抽象クラス・メソッドの構文と具体例
子ページはありません
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript で base URL を取得する方法|window.location.origin
- 4 YouTube Data API v3 エラー一覧|403・400・404 の原因と対処
- 5 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 6 3Dグラフィックスのソフト一覧|Blender・Metasequoiaと用途別の選び方
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- Visual Studio「デザイナーを表示できません」エラーの原因と対処 2026-10-28 12:06:00
- SSH 認証に失敗しました。再試行してください の対処 2026-10-28 12:06:00
- SSH2 秘密鍵の読み込みに失敗しました の原因と対処 2026-10-28 12:06:00
- TeraTerm のよくあるエラーと対処法完全ガイド — Connection refused / 2026-10-28 12:06:00
- Visual Studio エラー一覧|コンパイルエラー・警告の確認方法と対処 2026-10-28 11:39:57
- Whitelabel Error Page の原因と消し方|Spring Boot のエラーページ 2026-10-28 11:39:57
- Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法 2026-10-28 11:39:57
- SQL WHERE 句完全ガイド 2026-10-28 11:39:57
- SQL JOIN 完全ガイド (INNER/LEFT/RIGHT/FULL OUTER) 2026-10-28 11:39:57
- tomcat の起動 / 停止ログと catalina.log・catalina.out の違い 2026-10-28 10:24:23
- Tomcat の起動確認方法 5 つ|localhost:8080・ポート・プロセス・ログ 2026-10-28 10:24:23
- Oracle 19c COMMITの使い方: 暗黙コミット・自動確定・応答不明時の確認 2026-10-28 09:59:09
- Oracle 19c DELETE文|削除対象の確認・COMMIT前の判断・ROLLBACKの条件 2026-10-28 09:59:09
- Oracle 19c INSERT文|INSERT ALL・SELECT・RETURNINGとMERGEの使い分け 2026-10-28 09:59:09
- Oracle 19cのトランザクション制御|COMMIT・ROLLBACK・分離レベルと接続設定 2026-10-28 09:59:09