Menu

PHPの抽象クラス:抽象メソッドと使いどころ

PHPの抽象クラスはabstract class Nameと宣言し、インスタンスを作れません。継承されるために存在するクラスです。プロパティ、コンストラクタ、完成したメソッドに加え、すべての子クラスが実装しなければならない本体のないabstractメソッドを持てます。

このページのコードはエディタで実行できます - 編集してすぐに結果を確認できます。

PHPの抽象クラスはabstract class Nameで宣言し、newで作ることはできません。ほかのクラスの土台で、プロパティ、コンストラクタ、完成したメソッドに加え、すべての子クラスが実装しなければならない本体のないabstractメソッドを持てます。

describe()はShapeに1回だけ書かれ、各子が提供するarea()を呼びます。抽象クラスがそのメソッドの存在を保証するので、describe()はそれに頼れます。

抽象クラスはnewで作れない

抽象クラスはわざと不完全にしてあります。Shape::area()には本体がないので、素のShapeオブジェクトには実行するものがありません。PHPはそれを作ることを拒否し、Errorを投げます。

抽象メソッドのルール

抽象メソッドは、本体の代わりにシグネチャとセミコロンを持ちます。各子は、互換性のあるシグネチャと、同じかより広い可視性でそれを実装しなければなりません。abstract protectedのメソッドは子でprotectedかpublicにできますが、privateにはできません。抽象メソッドを1つでも持つクラスは、それ自体をabstractとして宣言する必要があります。

抽象メソッドを実装しない子は、それ自体もabstractとして宣言してメソッドを自分の子に任せるのでない限り、スクリプトのどこも実行される前に止めてしまいます。

PHP Fatal error:  Class Square contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Shape::area) in /home/index.php on line 3

テンプレートメソッドパターン

抽象クラスを書くいちばんよくある理由は、決まった手順の並びがあり、そのうちのいくつかの手順だけが違う場合です。基底クラスがfinalメソッドで手順の並びを持ち、子が手順を埋めます。ここでは同じレポートを、プレーンテキストとHTMLの表として実行します。

実行すると、Pageタブにプレーンテキスト版の上にHTMLの表が表示されます。open()とclose()にはデフォルトの本体があるので、わざわざオーバーライドするのはHtmlReportだけです。row()は妥当なデフォルトがないので抽象にしています。render()をfinalにすれば、子が手順の順番を変えるのを防げます。

抽象クラスはインターフェースを実装できる

抽象クラスはimplementsを宣言し、インターフェースのメソッドの一部を子に任せることができます。インターフェース(型)と基底クラス(共有コード)を組み合わせる標準的な方法です。

コードはインターフェースCacheで型宣言しているので、(すでにほかのクラスを継承しているために)BaseCacheを継承できないクラスも、Cacheを直接実装できます。

抽象クラスを使うとき、使わないとき

ファミリーのクラスが本当のコード、つまりプロパティ、コンストラクタ、全員に共通のメソッドを共有しているときに抽象クラスを選びましょう。基底クラスが抽象メソッドしか持たないなら、それは姿を変えたインターフェースで、クラスはインターフェースならいくつでも実装できるのにクラスは1つしか継承できないので、インターフェースのほうがよい選択です。関係のないクラスの間でいくつかのヘルパーメソッドを共有したいだけなら、1つの親の下に無理にまとめず、トレイトを使います。

abstract classと書く前の簡単なテストです。すべての子が本当に基底の一種でしょうか(CircleはShapeです)。正直な答えが「これらの一種である」ではなく「これができる」なら、インターフェースを書きましょう。

よくある質問

PHPの抽象クラスとは何ですか?

abstract class Nameで宣言し、newで作れないクラスです。ほかのクラスの土台になるもので、プロパティ、コンストラクタ、通常のメソッドを持て、各子クラスが実装しなければならないabstractメソッドを宣言できます。

PHPの抽象メソッドとは何ですか?

abstract付きで本体なしに宣言したメソッドです:abstract protected function render(array $rows): string;。これを含むクラスはそれ自体をabstractとして宣言する必要があり、抽象でない子クラスはすべて互換性のあるシグネチャでそのメソッドを定義しなければなりません。

PHPの抽象クラスはコンストラクタを持てますか?

持てます。抽象クラスに対してnewは呼べませんが、そのコンストラクタは子クラスが作られるときに、自動で(子にコンストラクタがない場合)またはparent::__construct(...)を通して実行されます。

PHPで抽象クラスをインスタンス化できますか?

できません。抽象クラスにnew Shape()とするとErrorが投げられます:Cannot instantiate abstract class Shape。代わりに、たとえばnew Circle(2)のように具象の子クラスのオブジェクトを作ります。

PHPで抽象クラスを使うべきなのはどんなときですか?

関連するいくつかのクラスが本当のコード(プロパティ、コンストラクタ、共通のメソッド)を共有し、いくつかの手順だけが違うときです。共有するコードを抽象クラスに置き、違う手順を抽象として宣言します。共有するコードがなく、約束だけが必要ならインターフェースを使います。

Coddyのプログラミング言語のイラスト

Coddyでコードを学ぼう

始める