PHPのクラスの継承

クラスの継承とは、定義済みのクラスの機能を引き継いで、新しいクラスを定義することです。このとき、継承する基のクラスをスーパークラス(親クラス、基底クラス)といい、継承して新たに作られるクラスをサブクラス(小クラス、派生クラス)といいます。継承をうまく利用することで、より効率的にプログラミングすることができます。

クラスの継承

クラスを継承するには、クラス定義の際、クラス名の後にextendsキーワードでスーパークラスを指定します。継承して作られたサブクラスは、スーパークラスのプロパティやメソッドを使用することができます。ただし、アクセス修飾子でprivateに指定されたプロパティやメソッドは使用できません。

PHPでは、多重継承(複数のクラスを同時に継承)はできません。しかし、継承して作られたサブクラスをさらに継承することは可能です。下記の例では、サブクラスでスーパークラスに定義されたプロパティやメソッドを使用しています。

PHP

<?php
class Foo
{
  private $private = 'private';
  protected $protected = 'protected';
  public $public = 'public';
  public static function staticFunc()
  {
    echo "Foo's staticFunc()", PHP_EOL;
  }
}
class FooChild extends Foo
{
  public function echoProp()
  {
    echo $this->private, PHP_EOL; // 出力:Notice: Undefined property
    echo $this->protected, PHP_EOL; // 出力:protected
    echo $this->public, PHP_EOL; // 出力:public
  }
}
class FooGrandChild extends FooChild
{
}
$fooChild = new FooChild();
$fooChild->echoProp();
$fooGrandChild = new FooGrandChild();
$fooGrandChild->echoProp();
FooChild::staticFunc(); // 出力:Foo's staticFunc()
FooGrandChild::staticFunc(); // 出力:Foo's staticFunc()
?>

parentキーワード

parentキーワードとスコープ定義演算子"::"を使うことで、サブクラスからスーパークラスにアクセスすることができます。下記の例では、parent::を通して、サブクラスのコンストラクタからスーパークラスのコンストラクタを呼んでいます。

また、下記のようにサブクラスでコンストラクタを定義した場合、スーパークラスのコンストラクタは自動では呼ばれなくなります。サブクラスでコンストラクタを定義しなかった場合は、スーパークラスのコンストラクタが自動で呼ばれます。

PHP

<?php
class Foo
{
  protected $name = 'Foo';
  public function __construct($name)
  {
    $this->name = $name;
    echo $this->name . "'s __construct().", PHP_EOL;
  }
}
class FooChild extends Foo
{
  public function __construct($name, $message)
  {
    parent::__construct($name);
    echo $message, PHP_EOL;
  }
}
$fooChild = new FooChild('FooChild', 'Hello world.');
/* 出力:
FooChild's __construct().
Hello world.
*/
?>

オーバーライド

オーバーライドとは、サブクラスでスーパークラスのメソッドやプロパティを上書きすることです。PHPでは、オーバーライドの特別な構文はなく、スーパークラスと同じ名前のプロパティやメソッドをサブクラスで定義するとオーバーライドされます。

メソッドをオーバーライドする場合、基本的にスーパークラスと引数が同じでなければいけませんが、デフォルト値を持つ引数を追加することはできます。

PHP

<?php
class Foo
{
  protected $name = 'Foo';
  public function echoName($greeting)
  {
    echo $greeting . ' ' . $this->name . '.', PHP_EOL;
  }
}
class FooChild extends Foo
{
  protected $name = 'FooChild';
  public function echoName($greeting, $note = 'オーバーライドしました。')
  {
    echo $greeting . ' ' . $this->name . '.', PHP_EOL;
    echo $note, PHP_EOL;
  }
}
$fooChild = new FooChild();
echo $fooChild->echoName('Hello');
/* 出力:
Hello FooChild.
オーバーライドしました。
*/
?>

finalキーワード

サブクラスでオーバーライドさせたくないメソッドは、finalキーワードを付けて定義することでオーバーライドを禁止することができます。また、継承させたくないクラスは、finalキーワードを付けて定義することで継承できなくなります。しかし、プロパティをfinalで宣言することはできません。

PHP

<?php
class Foo
{
  protected $name = 'Foo';
  final public function echoName($greeting)
  {
    echo $greeting . ' ' . $this->name . '.', PHP_EOL;
  }
}
final class FooChild extends Foo
{
  protected $name = 'FooChild';
  /* 出力:Fatal error: Cannot override final method
  public function echoName($greeting, $note = 'オーバーライドしました。')
  {
    echo $greeting . ' ' . $this->name . '.', PHP_EOL;
    echo $note, PHP_EOL;
  }
  */
}
/* 出力:Fatal error: Class FooGrandChild may not inherit from final class (FooChild)
class FooGrandChild extends FooChild
{
}
*/
$fooChild = new FooChild();
echo $fooChild->echoName('Hello'); // 出力:Hello FooChild.
?>

遅延静的束縛

PHP5.3からは、遅延静的束縛が利用できます。遅延静的束縛により、呼び出し元のクラスを参照できるため、サブクラスで定義したstaticメソッド、staticプロパティ、クラス定数にスーパークラスからアクセスすることができます。

下記の例では、Fooクラスで定義したメソッド内で、staticキーワードとスコープ定義演算子"::"でアクセスすることにより、呼び出し元のFooChildクラスのstaticメソッドにアクセスすることができています。

PHP

<?php
class Foo
{
  public static function call()
  {
    self::echoName();
    static::echoName();
  }
  public static function echoName()
  {
    echo 'This is Foo.', PHP_EOL;
  }
}
class FooChild extends Foo
{
  public static function echoName()
  {
    echo 'This is FooChild.', PHP_EOL;
  }
}
FooChild::call();
/* 出力:
This is Foo.
This is FooChild.
*/
?>