PHP
 Computer >> コンピューター >  >> プログラミング >> PHP

PHPの抽象クラス(Abstract Class)とは?特徴と実装例をわかりやすく解説

はじめに

PHP5以降、本格的なオブジェクト指向モデルが導入されました。オブジェクト指向の主な概念には、クラス、オブジェクト、カプセル化、ポリモーフィズム(多態性)、抽象クラスやfinalクラス、インターフェース、継承などがあります。

本記事では、その中でも「抽象クラス(Abstract Class)」に焦点を当て、PHPにおけるオブジェクト指向技術との関連や特徴を詳しく解説します。さらに、具体的なコード例を交えながら、抽象クラスの実装方法も学んでいきましょう。

詳細に入る前に、まずは抽象クラスの定義方法から確認しておきましょう。

抽象クラスの定義方法

クラス名の先頭にabstractキーワードを付けることで、そのクラスを抽象クラスとして宣言できます。抽象クラスとは、端的に言えば「抽象メソッドを含むクラス」のことです。抽象メソッドにはメソッド名と引数のみが定義され、処理本体(ボディ)は持ちません。

また、抽象クラスは直接インスタンス化(オブジェクト生成)できません。代わりに、子クラスで抽象メソッドの実装を定義し、その子クラスを使ってオブジェクトを生成します。

それでは、PHPの抽象クラスに関する重要なポイントを順番に見ていきましょう。

1. 抽象クラスは抽象メソッドと非抽象メソッドの両方を持てる

抽象クラス内には、実装を持つ通常のメソッド(非抽象メソッド)と、実装を持たない抽象メソッドを混在させて定義できます。

コード例:

<?php
    abstract class base {
      abstract function printdata();
      public function getdata() {
          echo "Tutorials Point";
      }
    }
    class child extends base{
      public function printdata(){
          echo "Good morning";
      }
    }
    $obj = new child();
    $obj->getdata();
?>

出力結果:

Tutorials Point

2. 直接インスタンス化できない

抽象クラスに対してnew演算子でオブジェクトを生成しようとすると、致命的なエラー(Fatal Error)が発生します。

コード例:

<?php
    abstract class AbstractClass{
      abstract protected function calculate();
      public function adddata() {
          echo "Addition done";
      }
    }
    $obj=new AbstractClass();
    $obj->adddata();
?>

出力結果:

Fatal error: Uncaught Error: Cannot instantiate abstract class AbstractClass

3. 子クラスでは同じか、より緩い可視性にする必要がある

親クラスでabstractとして宣言されたすべてのメソッドは、子クラス側で必ず定義しなければなりません。その際、メソッドのシグネチャ(可視性など)は親と同じか、より緩い(公開度の高い)ものである必要があります。

例えば、親クラスでprotectedとして宣言された抽象メソッドは、子クラスではprotectedまたはpublicで定義する必要があり、privateで定義することはできません。

コード例:

<?php
    abstract class AbstractBaseClass1{
      abstract public function addValue();
      abstract protected function getValue();
    }
    class ConcreteClass extends AbstractBaseClass1{
      protected function addValue() {
          return "ConcreteClass";
      }
      public function getValue() {
          return " Child Class";
      }
    }
    $classobj = new ConcreteClass;
    $classobj->addValue();
?>

出力結果:

Fatal error: Access level to ConcreteClass::addValue() must be public (as in class AbstractBaseClass1)

4. 抽象メソッドには処理本体を記述できない

abstractとして宣言されたメソッドは、シグネチャ(メソッド名・引数・可視性)の宣言のみが可能で、波括弧{}の中に処理を記述することはできません。一方、非抽象メソッドであれば、当然ながら処理本体を持つことができます。

コード例:

<?php
    abstract class ParentClass{
      abstract protected function printValue(){
          return "Good morning";
      }
    }
    class ClassA extends ParentClass{
      protected function printValue() {
          return "ConcreteClass1";
      }
    }
    $classobj = new ClassA;
    $classobj->printValue();
?>

出力結果:

PHP Fatal error:  Abstract function ParentClass::printValue() cannot contain body

5. 抽象メソッドを1つでも含むクラスは必ず抽象クラスとして宣言する

抽象クラスは抽象メソッドと非抽象メソッドの両方を持てますが、逆に「抽象メソッドを1つでも含むクラス」は必ずabstractキーワードを付けて抽象クラスとして宣言する必要があります。宣言を忘れるとエラーとなります。

コード例:

<?php
    class AbstractClass {
      abstract protected function getValue();
      public function printData() {
          echo " Welcome to Tutorials Point";
      }
    }
    $obj=new AbstractClass();
    $obj->printData();
?>

出力結果:

PHP Fatal error:  Class AbstractClass contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (AbstractClass::getValue)

6. 多重継承はサポートされない

PHPの抽象クラス(正確にはPHPのクラス全般)は、複数のクラスを同時に継承する「多重継承」をサポートしていません。

コード例:

<?php
    Abstract class SuperClass{
      public abstract function test();
      protected function welcome(){
          echo "Good morning";
      }
    }
    class ClassA extends SuperClass{
      public function test(){
          echo "Hello";
      }
      protected function welcome(){
          echo "Good afternoon";
      }
    }
    class ClassB extends SuperClass{
      public function test(){
          echo "Hello";
      }
      protected function welcome(){
          echo "Good evening";
      }
    }
    class ClassC extends ClassA, ClassB{
      public function test1(){
          $c = new self();
          $c->welcome();
      }
    }
?>

出力結果:

Error

解説:

この例では、test()メソッドとwelcome()メソッドを持つ抽象クラスSuperClassを宣言し、ClassAとClassBという具象クラスがそれぞれ継承しています。その後、ClassAとClassBの両方を継承しようとするClassCを作成しました。

しかし、ClassCのオブジェクトからwelcome()メソッドを呼び出した場合、PHPエンジンはClassAのwelcome()を呼ぶべきか、ClassBのwelcome()を呼ぶべきか判断できません。このような曖昧さ(いわゆる「ダイヤモンド継承問題」)を避けるため、PHPは多重継承をサポートしていないのです。

補足

  • 抽象クラスは、別の抽象クラスを継承(拡張)することができます。
  • 抽象クラスは、インターフェースの実装を提供することも可能です。
  1. PHPのget_class_methods()関数とは?使い方をわかりやすく解説

    get_class_methods()関数の概要PHPのget_class_methods()関数は、指定したクラスに定義されているメソッド名の一覧を取得するための関数です。引数に渡されたクラス(name_of_class)に定義されたすべてのメソッド名を配列として返し、エラーが発生した場合はNULLを返します。構文get_class_methods(class)パラメータname_of_class − メソッド名を取得したいクラス名を文字列またはオブジェクトで指定します。必須パラメータです。戻り値get_class_methods()関数は、name_of_c

  2. Javaの抽象クラスとは?基本ルールと実装例をわかりやすく解説

    Javaの抽象クラスとは宣言に「abstract」キーワードを含むクラスは、抽象クラスと呼ばれます。抽象クラスは、継承によって利用されることを前提とした設計用のクラスであり、オブジェクト指向プログラミングにおける重要な概念の一つです。抽象クラスの主な特徴抽象クラスには、抽象メソッド(本体を持たないメソッド。例:public void get();)が含まれる場合もあれば、含まれない場合もあります。ただし、クラス内に1つでも抽象メソッドが存在する場合、そのクラスは必ず abstract として宣言しなければなりません。abstract として宣言されたクラスは、インスタンス化(newによるオブジ