【PHP】クラスの継承(extends) - 既存クラスの定義を引き継ぐクラス

【PHP】クラスの継承(extends) - 既存クラスの定義を引き継ぐクラス

クラスには『クラスの継承』と呼ぶ仕組みがあります。

クラスの継承を使うことで、既存クラスの定義を引き継ぐクラスを定義することができます。

ここでは、継承について解説します。

検証環境

クラスの継承

クラスの継承は“クラス定義において、既存クラスの定義を引き継ぐこと”です。

スーパークラス

クラスの継承において、継承元をスーパークラスまたは親クラスと呼びます。

サブクラス

クラスの継承において、継承先をサブクラスまたは子クラスと呼びます。

サブクラスはスーパークラスのフィールドやメソッド等を使用できます。

基本構文

クラスの継承はextendsキーワードを使用します。

class サブクラス名 extends スーパークラス名 {
    // 定義 etc ...
}

通常のクラス定義に加えて、extendsキーワードとスーパークラス名を記述します。

サンプル

<?php

// 人間クラス
class Person {
    
    // 名前
    public $name;
    
    // コンストラクタ
    public function __construct( $name ) {
        $this->name = $name;
    }
    
    // あいさつ
    public function greeting() {
        echo "Hey!\n";
        echo "My name is ". $this->name . ".\n";
    }
    
}

// 教師クラス
___ih_hl_start
class Teacher extends Person {
    
}
___ih_hl_end

___ih_hl_start
$teacher = new Teacher('TANAKA');
___ih_hl_end

var_dump($teacher);

___ih_hl_start
$teacher->greeting();
___ih_hl_end

?>
$ php sample.php
object(Teacher)#1 (1) {
  ["name"]=>
  string(6) "TANAKA"
}
Hey!
My name is TANAKA.

23〜25行目はPersonクラスを継承したTeacherクラスの定義です。

Teacherクラスはフィールドやメソッドの定義がありませんが、スーパークラス(Personクラス)の$nameフィールドやコンストラクタ、greetingメソッドの定義を引き継ぎます。

引き継いだ定義はTeacherクラスから使用でき、実際に27行目ではTeacherクラスに引数があるコンストラクタは未定義ですが、引数を取ってオブジェクトを生成しており、この時にPersonクラスのコンストラクタが呼び出されています。

また、その後のvar_dump関数の出力から、そのオブジェクトはTeacherクラスであることが分かります。

31行目ではTeacherクラスのオブジェクトに対して、greetingメソッドを呼び出していますが、実行結果からPersonクラスに定義したgreetingメソッドの処理が実行されており、$nameフィールドにはコンストラクタの引数に渡した'TANAKA'が記憶されていることが分かります。

このようにサブクラスはスーパークラスの定義を引き継ぐことが可能です。

クラスの拡張

サブクラスは新たにフィールドやメソッド等の定義を追加し、拡張することができます。

例えば次のコードは上記サンプルのTeacherクラスに新しく定義を追加したコードです。

<?php

// 人間クラス
class Person {
    
    // 名前
    public $name;
    
    // コンストラクタ
    public function __construct( $name ) {
        $this->name = $name;
    }
    
    // あいさつ
    public function greeting() {
        echo "Hey!\n";
        echo "My name is ". $this->name . ".\n";
    }
    
}

// 教師クラス
class Teacher extends Person {
    
    // 担当科目
    ___ih_diff_start
+    public $subject = 'Programming';
    ___ih_diff_end
    
    // 授業
    ___ih_diff_start
+    public function lesson() {
+        echo $this->subject . ' : ' . $this->name;
+    }
    ___ih_diff_end
    
}

$teacher = new Teacher('TANAKA');

___ih_diff_start
-var_dump($teacher);
___ih_diff_end

___ih_diff_start
-$teacher->greeting();
+$teacher->lesson();
___ih_diff_end

?>
$ php sample.php
Programming : TANAKA

※ 行先頭にマイナス-があるコードは削除という意味です。

26行目の$subjectフィールドと29〜31行目のlessonメソッドが新しく追加(拡張)した定義です。

Personクラスを継承するため、lessonメソッドの処理で、$nameに擬似変数$thisを経由してアクセスできます。

38行目でlessonメソッドを呼び出しており、実行結果から正常に処理が行われていることが分かります。

このように、継承では既存クラスを引き継ぎ、新しくフィールドやメソッドを追加することで拡張したクラスを定義することが可能です。

アクセス修飾子の制限

アクセス修飾子がprivateなプロパティ(フィールドやメソッド)は定義を引き継ぐことができません。

アクセス修飾子については別途解説しますが、ここでは、publicまたはprotectedなプロパティのみ定義を引き継げることを覚えておきましょう。

演習問題

問題1

次の実行結果になるプログラムを作成してください。
なお、下記条件を満たすものとします。

  • 下記表の3つのクラスを作成する
  • 実行結果になるように各クラスのインスタンスを使う
クラス 英記 継承元 フィールド メソッド
乗り物クラス Vehicle なし $distance(移動距離)
※ 初期値は0
move()
→ "移動します。"を出力し、$distanceの値を20加算する。
display_distance()
→ $distanceの値を出力
車クラス Car Vehicle なし run()
→ "走行します。"を出力し、$distanceの値を50加算する。
飛行機クラス Airplane Vehicle なし fly()
→ "飛行します。"を出力し、$distanceの値を50加算する。
===== 乗り物クラスのインスタンス =====
移動します。
移動距離 : 20km
=====  車クラスのインスタンス  =====
走行します。
走行します。
移動距離 : 100km
===== 飛行機クラスのインスタンス =====
飛行します。
飛行します。
飛行します。
移動距離 : 2400km

問題2

次の実行結果になるプログラムを作成してください。
なお、下記条件を満たすものとします。

  • 下記表の3つのクラスを作成する
  • 実行結果になるように各クラスのインスタンスを使う
クラス 英記 継承元 フィールド メソッド
チケットクラス Ticket なし $price(料金) display_price()
→ $priceの値を出力
ライブチケット LiveTicket Ticket $place(場所) info()
→ 場所と料金を出力
※ 料金の出力はdisplay_price()を使う
ライブ配信チケット LiveStreamingTicket Ticket $url(URL) info()
→ URLと料金を出力
※ 料金の出力はdisplay_price()を使う
===== ライブチケットクラスのインスタンス =====
場所 : ライブハウス
料金 : 8000円
=====  ライブ配信クラスのインスタンス  =====
URL : https://it-hack.net/live-streaming
料金 : 3000円