クラスの抽象化

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

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

例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' という名前のユーザー定義クラスや関数を含まないコードは、修正なしに動作します。