|
PHP4からオブジェクト指向的な機能・動作が改善されていますが、オブジェクト指向言語であるJavaとどの程度挙動が異なるか、ちょっとずつまとめてみようかと思います。基本的には、PHPマニュアルに記載されていなくて、「どうなるの?」と思ったことを主にやっています。
今回は、「abstractメソッドの実装を強制する」についてです。
PHPには、Javaでいうところの「public」「abstract」などのクラス修飾子はありませんので、基本的には「abstractメソッドの実装をサブクラスに強制する」ことはできません。しかし、強制するような仕組みをこちらで作ってしまうこともできちゃいます。
まず、[php-users 6028]の黒木さんから頂いたPHPスクリプトとメールの内容です。
zip形式
tgz形式
ML ではお世話になっております、黒木です。デザインパタンを実装
するのにあると便利な Abstract メソッドを再現する為のクラスをお送
りします。
使用方法は継承するだけです。一応内部で Iterator を利用してるので
そちらも添付致します。あまり出来は良くはありませんがとりあえず
抽象クラスもどきが使えます。メソッド呼び出しに呼び出し用メソッド
を利用するというのがちょっと不自然です(^^;
やはり慣れて来たらあまり必要なさそうなクラスでもあります。
黒木さんの実装方法ですが、以下のような感じです。
- abstractメソッド名は、先頭に「_」を付ける
- abstractメソッドをAbstractクラスのregistFuncメソッドで登録する(以下のサンプルスクリプト参照)
- サブクラスでAbstractクラスのcallメソッドを使って、abstractメソッドを呼び出す(以下のサンプルスクリプト参照)
●abstract.php
<?php
require( "Abstract.phtml" ) ;
require( "Iterator.phtml" ) ;
class hoge extends Abstract {
function hoge() {
$this->Abstract() ;
$this->registFunc( 'add' ) ;
$this->registFunc( 'sub' ) ;
}
}
class foo extends hoge {
function foo() {
$this->hoge() ;
$a = $this->call( 'add', 5, 6 ) ;
$b = $this->call( 'sub', 5, 6 ) ;
echo $a."<br>" ;
echo $b."<br>" ;
}
function _add( $a, $b ) { return $a + $b ; }
}
$foo = new foo();
?>
●出力結果(_subメソッドを実装なかった場合)
Abstruct function _sub is not defined
●出力結果(全てのabstractメソッドを実装した場合)
11
-1
Abstractクラスを見ていただくと分かると思いますが、get_class_methods関数やfunc_get_args関数を使ってabstractメソッドの実装状態やその引数をチェックし、動的にPHPのコマンドを作成し、evalした結果を返しています。よくできていて、非常に参考になります。
で、私も寝ぼけた頭(午前3時頃です(^-^;)で作ってみました。以下は、黒木さんのメールの返信の一部です。
>抽象クラスもどきが使えます。メソッド呼び出しに呼び出し用メソッド
>を利用するというのがちょっと不自然です(^^;
んー。辛いところですね(^-^;
で、寝ぼけてるかも知れない頭で私も作ってみましたので、添付
しました。でも、AbstractのハズがConcreteになっちゃってます(^-^;
メソッドの中では自爆(?)するためのstaticメソッドを呼び出し
ているだけですが、実装しないと自爆しちゃいますので、一応実装
を強制しているかな?と思います。
私の実装方法ですが、以下のような感じです。
- Abstractクラスに自爆用メソッドsetを用意する
- abstractメソッドは、Abstractクラスのsetメソッドをデフォルト実装する(「マーク付け」な感じですね。ただ、この時点ですでに「abstract」ではないですが。。。)
- 実装しているかどうかのチェックは、実行時にそのメソッドが呼び出されたときのみ(実装しなくても呼び出されなければエラーにならないですが、abstractメソッドとして定義する意味がないと思います。。。)
かなり単純ですが、一応実装を強制しているかな?と思います。以下がサンプルです。
●abstract2.php
<?php
class Abstract
{
function set() { die("Abstruct function is not defined"); }
}
class hoge
{
function hoge() {}
function add($a, $b) { Abstract::set(); }
function sub($a, $b) { Abstract::set(); }
}
class foo extends hoge
{
function foo() {}
function add($a, $b) { return $a + $b ; }
function div($a, $b) { Abstract::set(); }
}
class bar extends foo
{
function bar() {}
function sub($a, $b) { return $a - $b ; }
}
$bar = new bar();
echo "add=" . $bar->add(5, 6) . "<br>";
echo "sub=" . $bar->sub(5, 6) . "<br>";
echo "div=" . $bar->div(5, 6) . "<br>";
?>
●出力結果(divメソッドを実装なかった場合)
add=11
sub=-1
Abstruct function is not defined
●出力結果(全てのabstractメソッドを実装した場合)
add=11
sub=-1
div=0.83333333333333
|