PHP アドバンス

PHP OOP - Inheritance(継承)

1. PHP - Inheritance(継承)

PHP OOPにおけるInheritance(継承)とは、子クラス(Child class)が親クラス(Parent class)からすべての public および protected なプロパティとメソッドを引き継ぐことができる仕組みです。さらに、子クラスは独自のプロパティやメソッドを追加して機能を拡張することも可能です。

       注意: 親クラスの private メソッドやプロパティには、子クラスからアクセスすることはできません。

継承したクラスを定義するには、extends キーワードを使用します。

以下の例では、Strawberry クラスが Fruit クラスを継承しています。これにより、Strawberry クラスは Fruit クラスの public$name$color プロパティ、および __construct()intro() メソッドを利用できるようになります。また、Strawberry クラス独自のメソッドである message() も持っています。

<?php
// 親クラス (Parent class)
class Fruit {
  public $name;
  public $color;

  public function __construct($name, $color) {
    $this->name = $name;
    $this->color = $color;
  }

  public function intro() {
    echo "この果物は {$this->name} で、色は {$this->color} です。<br>";
  }
}

// Strawberry は Fruit を継承 (Inherited) しています
class Strawberry extends Fruit {
  public function message() {
    echo "私は果物でしょうか、それともベリー類でしょうか? ";
  }
}

$strawberry = new Strawberry("ストロベリー", "赤");
$strawberry->intro();   // 親クラスのメソッドを呼び出し
$strawberry->message(); // 自身のメソッドを呼び出し
?>

2. Inheritance と Protected アクセス修飾子

以前の章で、protected なプロパティやメソッドは「そのクラス内、およびそのクラスから派生したクラス」からアクセスできると学びました。これが具体的にどういう意味か、例を見てみましょう。

まず、クラスの外部から protected メソッドを呼び出そうとした場合のエラー例です。

<?php
class Fruit {
  public $name;
  public $color;

  public function __construct($name, $color) {
    $this->name = $name;
    $this->color = $color;
  }

  protected function intro() {
    echo "この果物は {$this->name} で、色は {$this->color} です。";
  }
}

class Strawberry extends Fruit {
  public function message() {
    echo "私は果物でしょうか、それともベリー類でしょうか? ";
  }
}

// 3つのメソッドをクラス外部から呼び出してみます
$strawberry = new Strawberry("ストロベリー", "赤"); // OK. __construct() は public
$strawberry->message(); // OK. message() は public
// $strawberry->intro();   // エラー。intro() は protected なので外部からは呼べません
?>

上記の例では、protected メソッド(intro())をクラスの外から呼び出そうとしたため、エラーが発生します。

次に、子クラスの内部から protected メソッドを呼び出す正しい例を見てみましょう。

<?php
class Fruit {
  public $name;
  public $color;

  public function __construct($name, $color) {
    $this->name = $name;
    $this->color = $color;
  }

  protected function intro() {
    echo "この果物は {$this->name} で、色は {$this->color} です。";
  }
}

class Strawberry extends Fruit {
  public function message() {
    echo "私は果物でしょうか、それともベリー類でしょうか? ";
    // 派生クラス(子クラス)内から protected メソッドを呼び出す - OK
    $this->intro();
  }
}

$strawberry = new Strawberry("ストロベリー", "赤"); // OK. __construct() は public
$strawberry->message(); // OK. message() は public であり、その内部で intro() を呼び出しています
?>

この例は正常に動作します。なぜなら、protectedintro() メソッドを、継承先である Strawberry クラスの内部から呼び出しているからです。

3. 継承したメソッドのオーバーライド (Overriding)

継承されたメソッドは、子クラスで同名のメソッドを再定義することでオーバーライド(Overriding)、つまり上書きすることができます。

以下の例では、子クラス(Strawberry)の __construct()intro() メソッドが、親クラス(Fruit)の同名メソッドをオーバーライドしています。

<?php
class Fruit {
  public $name;
  public $color;

  public function __construct($name, $color) {
    $this->name = $name;
    $this->color = $color;
  }

  public function intro() {
    echo "この果物は {$this->name} で、色は {$this->color} です。";
  }
}

class Strawberry extends Fruit {
  public $weight;

  // 親クラスのコンストラクタをオーバーライド
  public function __construct($name, $color, $weight) {
    $this->name = $name;
    $this->color = $color;
    $this->weight = $weight;
  }

  // 親クラスの intro メソッドをオーバーライド
  public function intro() {
    echo "{$this->name} は {$this->color} 色で、重さは {$this->weight} グラムです。";
  }
}

$strawberry = new Strawberry("ストロベリー", "赤", 50);
$strawberry->intro();
?>

4. final キーワード

final キーワードを使用すると、クラスの継承を禁止したり、メソッドのオーバーライドを防止したりすることができます。

以下の例は、クラスの継承を禁止する方法を示しています。

<?php
final class Fruit {
  // クラスのコード
}

// エラーになります:final クラスは継承できません
class Strawberry extends Fruit {
  // 子クラスのコード
}
?>

次の例は、メソッドのオーバーライドを禁止する方法を示しています。

<?php
class Fruit {
  final public function intro() {
    // メソッドのコード
  }
}

class Strawberry extends Fruit {
  // エラーになります:final メソッドはオーバーライドできません
  public function intro() {
    // オーバーライドしようとするコード
  }
}
?>