1. ホーム 
  2. 備忘録 
  3. PHP

継承

オブジェクトの継承

継承とは、継承元クラスのメンバやメソッドを引き継ぐことでクラスを拡張する方法である

継承元のことを親クラス、継承先のことを子クラスという

PHP での継承は extends を使用する

子クラスが親クラスから参照できる変数やメソッドはアクセスレベルが public や protected のものであり、private は参照できないことに注意する

class Animal
{
  /** @var string カテゴリ名 */
  public $category_name;
  /** @var string 名前 */
  protected $name;
  /** @var integer 年齢 */
  private $age;

  protected function getAge()
  {
    return $this->age;
  }

  protected function setAge( $age )
  {
    $this->age = $age;
  }
}

class Dog extends Animal
{
  public function __construct( $name, $age )
  {
    $this->category_name = '犬';
    $this->name = $name;
    // $this->age = 0; age のアクセスレベルは private の設定なので子クラスでは直接変数の値を変更できない
    // その代わりにアクセサメソッドを用意してあるのでそちらを使う
    $this->setAge( $age );
  }

  public function getMessage()
  {
    return sprintf( '私は%sの%sだワン!!年齢は%d歳だワン!!', $this->category_name, $this->name, $this->getAge() );
  }
}

$instance = new Dog( 'ウィル', 16 );
echo $instance->getMessage(); // 私は犬のウィルだワン!!年齢は16歳だワン!!

オーバーライド

子クラスで親クラスと同じ変数名やメソッド名を定義することでオーバーライドすることができる

この際アクセス権を緩めることはできるが、厳しくすることはできない(ただしコンストラクタだけ例外的に厳しくすることができる)
例えば public だったものを protected に変えることはできないし、read-write だったものを readonly に変えることもできないので注意すること


オーバーライドした上で子クラスから親クラスのメソッドを呼び出したい場合は、parent:: を使用する

class A
{
  public $val1;
  protected readonly int $val2;

  public function __construct( $value1, $value2 )
  {
    $this->val1 = $value1;
    $this->val2 = $value2;
  }

  protected function foo()
  {
    return 'foo_A';
  }

  public function bar()
  {
    return 'bar_A';
  }
}

class B extends A
{
  // protected $val1; public -> protected はアクセス権が厳しくなっているのでNG
  // public readonly int $val1; read-write -> readonly はNG
  // protected $val2; readonly -> read-write でもNG;
  public readonly int $val2; // protected readonly -> public readonly はアクセス権が緩くなっているのでOK

  //  protected -> private でアクセス権が厳しくなっているのでNG
  //  private function foo()
  //  {
  //    return 'foo_B';
  //  }

  // protected -> public でアクセス権が緩くなっているのでOK
  public function foo()
  {
    return 'foo_B';
  }

  public function bar()
  {
    return 'bar_B';
  }

  // 親クラスの bar() を呼び出す.
  public function parent_bar()
  {
    return parent::bar();
  }
}

$test = new B( 1, 99 );
echo $test->foo(); // foo_B
echo $test->bar(); // bar_B
echo $test->parent_bar(); // bar_A

// val2 は 親クラスで protected readonly だが子クラスが public readonly に上書きしているのでアクセスできる
echo $test->val1 + $test->val2; // 100;

final キーワード

場合によってはメソッドを上書きしてほしくない、またはクラスを継承してほしくないときがある

その時は final の修飾子をつけることで上書きや継承を禁止することができる

final public function method()
{
  return "このメソッドは上書き禁止です";
}

final class BaseClass
{
  // このクラスは継承禁止です;
}

    参考文献

  1. 公式ドキュメント