phpでクラスライブラリを書いていてふと思った。
DBのテーブルに紐付いたクラスというものを書いていて、それらは共通の基底クラスを持っている。基底クラスはコンストラクタでabstractなメソッドをコールする部分があり、それによって派生クラスで定義されたDBのテーブル定義を取得している。基底クラスは当然abstractだ。
外部からテーブルの定義だけ取得したいなと思ったときにいちいち派生クラスのインスタンスを生成するのは面倒だと思って、abstractなテーブル定義メソッドをstatic宣言してみたが、そうすると基底クラスのコンストラクタがこけてしまった。
Fatal error: Cannot call abstract method kscObjectList::getTableDef() in /home/…../ksc_……class.php on line 50
基底クラスのコンストラクタは、定義された派生クラス側のメソッドをコールしようとせずにabstractなままの基底クラス側のメソッドをコールしようとしてこけている。それにロード時に文法エラーでこけてるのではなく、インスタンスの生成時に実行時エラーでこけている。
ちょっと待てよ?abstractメソッドは派生クラスで定義する事を義務付けるために存在するはずだ。定義しないとどうなる?インスタンスを生成できなくなる。インスタンスを生成できなくする事によって、定義を強制しているというのが自分のもっている感覚だ。
ではstaticなabstractメソッドが基底クラスにあったとする。派生クラス側で定義しないと、派生クラスのインスタンス生成時にエラーになり、派生クラス側で定義すると、インスタンスが生成できるとする。でもstaticなメソッドから、生成されたインスタンスは(パラメータとして外部から渡されたりしない限り)見えないから、staticメソッドの定義強制をインスタンスの生成許可/禁止によって制御するのはよく考えれば非常におかしな話だ。
でも、ここのページにあるように、Factoryメソッドの定義を派生クラスに強制させるために、定義しないとエラーになるstaticメソッドを基底クラスで宣言するというのは意味があるだろう。
そもそもabstractというキーワードは(私が思うに)インスタンス生成時に実行時エラーになるというニュアンスで通っている気がするので、コンパイル時(phpではロード時?)にエラーになるstaticな抽象メソッドのキーワードがあればいいのになあ、と思った。実際には、現時点ではabstractなstaticメソッドは書けません。5.3.0以降に搭載されるLate Static Bindingにしても、基底クラスから派生クラスのstaticメソッドを呼べるけど基底クラス側を抽象化する機能はないらしい。