[PHP] 抽象クラスとインターフェース

PHPの抽象クラスとインターフェースについてです。

抽象クラス

抽象クラスは継承される前提のクラスで、それ自体ではインスタンスを生成することが出来ないクラスです。

インスタンスは生成できませんが、メソッドやプロパティは持つことが可能で、これらは基本的に継承されたサブクラスから呼ばれて扱われます。

抽象クラスの最大の特徴は、抽象メソッドを持つことが可能です。抽象メソッドとは、処理を記載しないメソッドで、サブクラスでオーバーライドされて処理が実装されます。

抽象クラスを継承したサブクラスでは、抽象メソッドを必ずオーバーライドしなくてはなりません。

抽象クラスと抽象メソッドの定義構文

abstract class 抽象クラス名 {
    abstract function 抽象メソッド名(シグネチャ) : 戻り値(任意);
}

[実装例]抽象メソッドをオーバーライドする

コード

abstract class TestAbstract {
    abstract function printName(string $name) : void;
}

class Test extends TestAbstract {
    function printName(string $name) : void {
        print "Hello {$name}.\n";
    }
}

$test = new Test();
$test->printName("abstract");

実行結果

$ php test_abstract.php
Hello abstract.

[実装例]抽象クラスからサブクラスに継承されたメソッドを実行する

抽象クラスに定義されたメソッドから、サブクラスに継承されたメソッドを実行することが出来ます。

コード

以下の例ではTestクラスでオーバーライドされたprintNameメソッドを、親クラスであるTestAbstractクラスのtestメソッドから呼び出しています。

抽象クラス事態はインスタンスを持つことはできませんが、サブクラスであるTestクラスのインスタンスがあるため、testメソッド内で$thisキーワードが使用できます。

abstract class TestAbstract {
    abstract public function printName(string $name);
    public function test() {
        $this->printName(__CLASS__ . "->" . __FUNCTION__);        
    }
}

class Test extends TestAbstract {
    public function printName(string $name) {
        print "Hello {$name}.\n";
    }
}

$test = new Test();
$test->test();

実行結果

$ php test_abstract.php
Hello TestAbstract->test.

[間違った実装例]抽象クラスのインスタンスを生成する

抽象クラスのインスタンスを生成しようとすると実行時にエラーが発生します。

コード

abstract class TestAbstract {
    abstract function printName(string $name) : void;
}

$test = new TestAbstract();

実行結果

$ php test_abstract.php

Fatal error: Uncaught Error: Cannot instantiate abstract class TestAbstract in .\test_abstract.php:24
Stack trace:
#0 {main}
  thrown in .\test_abstract.php on line 24

[間違った実装例]抽象メソッドをオーバーライドしていない

抽象クラスを継承した場合、継承したクラスでは全ての抽象メソッドをオーバーライドしなくてはなりません。オーバーライドしていない抽象メソッドがあると、実行時にエラーが発生します。

コード

abstract class TestAbstract {
    abstract function printName(string $name) : void;
    abstract function printValue(string $value) : void;
}

class Test extends TestAbstract {
    public function printName(string $name) : void {
        print "Hello {$name}.\n";
    }
}

$test = new TestAbstract();

実行結果

$ php test_abstract.php

Fatal error: Class Test contains 1 abstract method and must therefore be declared
    abstract or implement the remaining methods (TestAbstract::printValue) in
    .\test_abstract.php on line 25

重要ポイント

  • 抽象クラスのインスタンスを生成することはできない
  • 抽象メソッドは継承したサブクラスで全てオーバーライドしなくてはいけない
  • 抽象クラスには抽象メソッド以外に、通常のメソッドや属性を持つことが出来る

インターフェース

インターフェースは抽象クラスと似ていて、抽象メソッドを持ち、それを扱うクラスによって処理が実装されます。インターフェースの場合はこれを継承ではなく「実装する」と言います。

抽象クラスと同じく、インターフェース事態でインスタンスを生成することはできません。ただし、中身の処理のあるメソッドやプロパティは定義することが出来ません。

また、抽象クラスと決定的に違う最大の特徴は、抽象クラスが多重継承できないのに対して、インターフェースは複数のインターフェースを一度に実装することが出来ます。

抽象クラスはすべてのメソッドをオーバーライドしなくてはならないため、不要なメソッドがあっても処理を実装しなくてはなりません。インターフェースの場合はインターフェース事態を細分化し、必要なインターフェースのみを実装すればよいので、上長的なコードを排除可能です。

インターフェースと抽象メソッドの定義構文

インターフェースの定義と抽象メソッドの定義にabstractキーワードは必要ありません。

interface インターフェース名 {
    function メソッド名(シグネチャ) : 戻り値(任意);
}

[実装例]インターフェースを実装する

コード

interface IShape {
    function getArea() : float;
}

class Square implements IShape {
    function getArea() : float {
        return (float) 1.125;
    }
}

$square = new Square();
var_dump($square->getArea());

実行結果

$ php test_interface.php
float(1.125)

重要ポイント

  • インターフェースのインスタンスを生成することはできない
  • 抽象メソッドは実装したクラスで全てオーバーライドしなくてはいけない
  • インターフェースには抽象メソッド以外に、定数のみ記述可能(具象メソッドやプロパティは定義できない)

コメント

このブログの人気の投稿

docker-compose up で proxyconnect tcp: dial tcp: lookup proxy.example.com: no such host

docker-compose で起動したweb、MySQLに接続できない事象

【PHP】PHP_CodeSnifferを使う(コーディングルールのカスタマイズ)