クラスの応用
継承・インターフェース・抽象クラス・トレイト
書けるようになったクラスを「継承」「抽象化」「インターフェース」「static」「定数」「final」で本格的な設計に育てるトピック。コードの再利用と契約 (interface) を扱う。
このトピックで身につくこと
extendsで既存クラスを継承し、必要な部分だけ書き換えられる- 抽象クラスとインターフェースの違いを説明できる
staticを使うべき場面 (共有カウンタ / ユーティリティ) を判断できるconstでマジックナンバーを排除できるfinalでクラス設計の意図を表現できる
前提知識の要点
クラスの基礎 (定義・new・プロパティ・メソッド・$this・コンストラクタ・アクセス修飾子) を理解していれば始められる。他のトピックの README を読み返さずに class-advanced を単独で開始できる ように、以下を圧縮しておく。
1. クラス定義・new・$this・コンストラクタ
<?php
class User {
public string $name;
public function __construct(string $name) {
$this->name = $name;
}
public function greet(): string {
return "こんにちは、{$this->name}";
}
}
$u = new User("太郎");
echo $u->greet();
// => こんにちは、太郎押さえどころは 4 点:
class クラス名 { ... }で設計図public string $name;でプロパティ宣言__constructはnewした瞬間に呼ばれる- メソッド内では自分のプロパティを
$this->nameで参照
2. アクセス修飾子
class Account {
public int $id; // どこからでも触れる
private int $balance; // クラス内からしか触れない
protected int $secret; // 自分と子クラスから触れる (このトピックで使う)
}このトピックでは protected が継承時に重要になる。「private は子クラスからも見えない」「protected は子クラスから見える」だけ覚えておけばよい。
3. 関数の戻り値の型ヒント
function area(float $r): float {
return 3.14 * $r * $r;
}このトピックでは抽象メソッドやインターフェースで「戻り値の型を約束する」場面で出てくる。
ここまで読めれば ch01 から始められる。
chapter 一覧
| chapter | 内容 | 学習目標 |
|---|---|---|
ch01-inheritance/ |
継承 (extends) |
親クラスのプロパティ/メソッドを子で再利用できる |
ch02-override/ |
メソッドのオーバーライド | 子クラスで親のメソッドを上書きできる |
ch03-parent-call/ |
parent:: 呼び出し |
子から親のメソッド/コンストラクタを呼べる |
ch04-abstract/ |
抽象クラス (abstract) |
共通部分を抽象化し、子に実装を強制できる |
ch05-interface/ |
インターフェース (interface / implements) |
「どんなメソッドを持つか」だけを契約として宣言できる |
ch06-static/ |
static プロパティ/メソッド |
インスタンス化せずに使える共有領域を扱える |
ch07-const/ |
クラス定数 (const) |
変わらない値をクラスに紐づけられる |
ch08-final/ |
final クラス/メソッド |
継承・オーバーライドを禁止できる |
合計 8 chapter / 7 drill (ch07 は概念説明のみ・drill なし) / 所要 4〜5 時間 程度。継承と抽象化は概念が抽象的なので、ch01〜ch04 は急がず slide.md を 2 回読むくらいで丁度よい。
進め方
- 各 chapter の
slide.mdを読む (3〜5 分) drill/配下の問題を順番に解く (ch07 は読むだけ)- 採点:
php scripts/grade.php topics/class-advanced/<chapter>/drill/<drill>/
つまづきポイント
| 症状 | 多くの原因 |
|---|---|
Cannot instantiate abstract class |
abstract class を直接 new している。継承先のクラスを new する |
Class contains abstract methods and must be declared abstract |
抽象メソッドを実装し忘れている。interface も同じ |
Cannot override final method |
親が final で宣言したメソッドを子でオーバーライドしている |
parent:: で Undefined method |
スペル違い、または親にそのメソッドが存在しない |
static メソッドから $this が使えない |
static 内では $this は存在しない。self:: か static:: を使う |
implements が動かない |
インターフェースが定義しているメソッドを 1 つでも実装し忘れている (シグネチャ一致も必要) |
関連トピック
| トピック | 関係 |
|---|---|
| class | このトピックの前提 (クラスの基本) |
| exception | 継承を使ったカスタム例外を作る |
| function | 抽象メソッド / interface の戻り値型ヒントで再登場 |
トピックを並列で参照する全体地図は TOPICS_INDEX.md にある。
案件 (dojo_map.tsv) での参照
topic_slug chapter_dir
class-advanced topics/class-advanced/ch01-inheritance
class-advanced topics/class-advanced/ch04-abstract
class-advanced topics/class-advanced/ch05-interface
...
slug class-advanced で参照可。09-class-advanced / class-advanced どちらの path でもアクセスできる (シンボリックリンク)。