オブジェクト引数のクラス指定
関数もしくはクラスのメンバ関数が要求する引数がオブジェクトである場合、関数の定義時に引数の型にクラス名を指定すると、指定したクラスのインスタンスであるかをチェックし、問題がある時点で「E_ERROR」エラーを発生するようになります。以下のサンプルと結果をご覧下さい。
<pre>
<?php
class ANIMAL{}
class CAT extends ANIMAL{}
class DOG extends ANIMAL{}
class MACHINE{}
function animal_func(ANIMAL $obj){
echo '$obj must be an instance of \'ANIMAL\'.', "\n";
echo '$obj is an instance of \'', get_class($obj), "'.\n\n";
}
function cat_func(CAT $obj){
echo '$obj must be an instance of \'CAT\'.', "\n";
echo '$obj is an instance of \'', get_class($obj), "'.\n\n";
}
#指定されたクラスのオブジェクトを渡す
animal_func(new ANIMAL);
cat_func(new CAT);
#指定されたクラスの派生クラスのオブジェクトを渡す
animal_func(new CAT);
animal_func(new DOG);
#指定されたクラスの基底クラスのオブジェクトを渡す
/*
cat_func(new ANIMAL);
*/
#指定されたクラスの兄弟クラスのオブジェクトを渡す
/*
cat_func(new DOG);
*/
#指定されたクラスと無関係なクラスのオブジェクトを渡す
/*
animal_func(new MACHINE);
*/
?>
</pre>
$obj must be an instance of 'ANIMAL'. $obj is an instance of 'ANIMAL'. $obj must be an instance of 'CAT'. $obj is an instance of 'CAT'. $obj must be an instance of 'ANIMAL'. $obj is an instance of 'CAT'. $obj must be an instance of 'ANIMAL'. $obj is an instance of 'DOG'. (Fatal error:「CAT」クラスのインスタンスでなければならない) (Fatal error:「CAT」クラスのインスタンスでなければならない) (Fatal error:「ANIMAL」クラスのインスタンスでなければならない)
「animal_func()」関数の定義部で、「引数$obj」の左側に「ANIMAL」を付与していますが、これによって、「引数$obj」に渡されるべき引数が「ANIMAL」クラスのオブジェクトに限定されます。「cat_func()」関数は、「引数$obj」に渡されるべき引数を「CAT」クラスのオブジェクトに限定しました。
この様に定義された関数は、コール時に、指定されたクラス以外のクラスのオブジェクト、もしくはオブジェクト型以外の型の値が渡された時に「E_ERROR」エラーを発生します。これによって、その関数の使用法が限定され、その目的・役目が明確になるというメリットがあります。
で、結果を見ると、指定されたクラスではないクラスのオブジェクトが渡された場合でも正常にコールされている場合があります。指定したクラスの派生クラスのオブジェクトを渡した場合は正常にコールされています。
「“猫”は“動物”であるからOK」で、「“動物”は必ずしも“猫”ではないからNG」って事か。「CAT」クラスは「ANIMAL」クラスの特性を全て備えているからOKで、「ANIMAL」クラスは「CAT」クラスの特性を備えていないからNGって事ですかね。
と、この曖昧な説明では納得できないと思うので(何)、以下のサンプルと結果をご覧下さい。
<pre>
<?php
class ANIMAL{
public function action($what){
echo "Action of {$what}\n";
}
}
class CAT extends ANIMAL{
public function neko_punch(){
echo "NEKO PUNCH!!!\n";
}
}
function animal_func(ANIMAL $obj){
echo "****** begin animal_func() ******\n";
$obj->action("ANIMAL");
echo "****** end animal_func() ******\n\n";
}
function cat_func(CAT $obj){
echo "****** begin cat_func() ******\n";
$obj->action("CAT");
$obj->neko_punch();
echo "****** end cat_func() ******\n\n";
}
animal_func(new ANIMAL);
cat_func(new CAT);
animal_func(new CAT);
/*
cat_func(new ANIMAL);
*/
?>
</pre>
****** begin animal_func() ****** Action of ANIMAL ****** end animal_func() ****** ****** begin cat_func() ****** Action of CAT NEKO PUNCH!!! ****** end cat_func() ****** ****** begin animal_func() ****** Action of ANIMAL ****** end animal_func() ****** (Fatal error:「CAT」クラスのインスタンスでなければならない)
「animal_func()」関数は「ANIMAL」クラスのオブジェクトが引数に渡される事を想定し、関数内では「ANIMAL」クラスのオブジェクトが持つメソッドをコールします。一方「cat_func()」関数は「CAT」クラスのオブジェクトが引数に渡される事を想定し、関数内では「CAT」クラスのオブジェクトが持つメソッドをコールします。
ここでもし、「cat_func()」関数を、引数に「ANIMAL」クラスのオブジェクトを指定してコールする事を許可したらどうなるでしょうか?この関数内では「neko_punch()」メソッドをコールしますが、「ANIMAL」クラスのオブジェクトが渡された場合、「ANIMAL」クラスのオブジェクトは「CAT」クラスで定義された「neko_punch()」メソッドを持っていないので、「E_ERROR」エラーを発します。一方、「animal_func()」関数の方は、「CAT」クラスのオブジェクトが渡されても問題はありません。
要するに、“派生クラスは基底クラスの特性を全て継承して備えているからOKだが、基底クラスは派生クラスで追加された特性を備えないからNG”と、いう事です。