※当サイトの記事には、広告・プロモーションが含まれます。

PHP5で導入された、抽象(abstract)クラスとそのメソッド

インターフェイス(interface)と似て非なるもの、それが抽象(abstract)クラスらしいです。

PHPマニュアル(PHP: クラスの抽象化 - Manual )の説明によると、

クラスの抽象化

PHP 5 では、抽象クラスとメソッドが導入されました。
abstractとして定義されたクラスのインスタンスを生成することはできません。
1つ以上の抽象メソッドを含む全てのクラスもまた抽象クラスとなります。
abstractとして定義されたメソッドは、そのメソッドの外観を宣言するのみで、 実装を定義することはできません。

抽象クラスから継承する際、親クラスの宣言で abstract としてマークされた 全てのメソッドは、子クラスで定義されなければなりません。
加えて、 これらのメソッドは同等 (あるいはより緩い制約) の 可視性 で定義される必要があります。
例えば、抽象メソッドが protected として定義された場合、その関数の実装は protected または public のどちらかとして定義する必要があります。
private にすることはできません。
さらに、メソッドのシグネチャも必ず一致していなくてはなりません。
すなわち、型ヒント(タイプヒント)や必須引数の数についても同じでなければならないということです。

たとえば、子クラスでオプションの引数を定義しているけれども 抽象クラスのメソッドのシグネチャでは定義されていないという場合、 シグネチャの衝突は発生しません。
PHP 5.4 以降では、これがコンストラクタについても適用されるようになりました。
それより前のバージョンでは、コンストラクタのシグネチャは違ってもかまいませんでした。

シグネチャ(signature)

関数の名称とそれらの型情報の組を合わせたものをシグネチャと呼ぶが、プログラム内でシグネチャが唯一に決まれば、関数名やメソッド名、演算子の記号が重複していても呼び出すべき対象を唯一に決定することが出来る。

シグネチャーとは : JavaA2Z

 

例1 抽象クラスの例

<?php
abstract class AbstractClass
{
    
// 拡張クラスにこのメソッドの定義を強制する
    
abstract protected function getValue();
    abstract protected function 
prefixValue($prefix);

    
// Common method
    
public function printOut() {
        print 
$this->getValue() . "\n";
    }
}

class 
ConcreteClass1 extends AbstractClass
{
    protected function 
getValue() {
        return 
"ConcreteClass1";
    }

    public function 
prefixValue($prefix) {
        return 
"{$prefix}ConcreteClass1";
    }
}

class 
ConcreteClass2 extends AbstractClass
{
    public function 
getValue() {
        return 
"ConcreteClass2";
    }

    public function 
prefixValue($prefix) {
        return 
"{$prefix}ConcreteClass2";
    }
}

$class1 = new ConcreteClass1;
$class1->printOut();
echo 
$class1->prefixValue('FOO_') ."\n";

$class2 = new ConcreteClass2;
$class2->printOut();
echo 
$class2->prefixValue('FOO_') ."\n";
?>

上の例の出力は以下となります。

ConcreteClass1
FOO_ConcreteClass1
ConcreteClass2
FOO_ConcreteClass2

例2 抽象クラスの例 

<?php
abstract class AbstractClass
{
    
// 抽象メソッドでは、必須の引数だけを定義しています
    
abstract protected function prefixName($name);

}

class 
ConcreteClass extends AbstractClass
{

    
// 子クラスでは、親のシグネチャにないオプション引数を定義することもあるでしょう
    
public function prefixName($name$separator ".") {
        if (
$name == "Pacman") {
            
$prefix "Mr";
        } elseif (
$name == "Pacwoman") {
            
$prefix "Mrs";
        } else {
            
$prefix "";
        }
        return 
"{$prefix}{$separator} {$name}";
    }
}

$class = new ConcreteClass;
echo 
$class->prefixName("Pacman"), "\n";
echo 
$class->prefixName("Pacwoman"), "\n";
?>

上の例の出力は以下となります。

Mr. Pacman
Mrs. Pacwoman 

'abstract' という名前のユーザー定義クラスや関数を含まないコードは、修正なしに動作します。

 

⇩  シグネチャ(signature)がポリモーフィズムに深く関わっているということで、ポリモーフィズムなどについては下記サイトへ

phpにおける継承、抽象化、ポリモーフィズム再確認してみた - 雑想空間