クラスについて(タイプヒンティング)
PHP、というかスクリプト全般だけど、オブジェクト的な考え方というか、そういうのがゆるくなるような感じが時々ある。
というのも、ActionScript(スクリプトだけど)でちょっとコードを書いていたとき、インターフェースって改めてなんじゃ?
とふと思った。
JAVAなんかだとインターフェースの意義というか、そういうのが身にしみるのだが、正直PHPだと実感がない。
例えば以下のコード
アニマルというスーパークラスからキャットとドッグというサブクラスを派生させ、プリンタークラスで名前をプリントさせるという流れ。 PHPであれば別に何のことはない、当然といえば当然。 だけど、JAVAやC#なんかからしたらこれはとんでもないことだろう。 printerクラスのnamePrintメソッドにクラス渡しをしているけど、dogクラスとcatクラスそれぞれを渡している。 渡す型が宣言されているのでdogでもcatでも何でも渡せるというわけには行かない。 だから、JAVAやC#でれば namePrintForDog 及び namePrintForCat といった具合にそれぞれ特定のクラスを渡せるメソッドを作成するか、 インターフェース(あるいは抽象化クラス)を利用して受け渡しのクラスを汎用化することで利便性をはかる。これがポリモフィズムってわけだが。
前述のコードを実行してもPHPではなんのことなく動く。 更にいうなら、まったく仕組みの違うクラスを用意してnamePrintメソッドに渡したとしても・・・
さて、そこでPHPでクラス型に配慮した渡し方にコードを変えてみる。 ここではnamePrintできるのはdogクラスのみとしてみる。 といっても「コード1」のnamePrintメソッドの実装を以下のように変えるだけ。
JAVAなんかだとインターフェースの意義というか、そういうのが身にしみるのだが、正直PHPだと実感がない。
例えば以下のコード
//コード1
class animal{
private $name = "";
public function __construct($lname = NULL){
if(!is_null($lname)){
$this->name = $lname;
}//END_if
}//END_Function
public function getName(){
return $this->name;
}//END_Function
public function Iam(){
return get_class($this);
}//END_Function
}//END_Class
class cat extends animal{
}//END_Class
class dog extends animal{
}//END_Class
class printer{
public function __construct(){
}//END_Function
public function namePrint($obj){
echo "I am ".$obj->Iam() ."'s ".$obj->getName() ."<br>";
}//END_Function
}//END_Class
$d = new dog("ポチ");
$c = new cat("ミケ");
//移動クラスを作成
$pt = new printer();
$pt->namePrint($d);
$pt->namePrint($c);
結果は当然ながら
I am dog's ポチ I am cat's ミケとなる。
アニマルというスーパークラスからキャットとドッグというサブクラスを派生させ、プリンタークラスで名前をプリントさせるという流れ。 PHPであれば別に何のことはない、当然といえば当然。 だけど、JAVAやC#なんかからしたらこれはとんでもないことだろう。 printerクラスのnamePrintメソッドにクラス渡しをしているけど、dogクラスとcatクラスそれぞれを渡している。 渡す型が宣言されているのでdogでもcatでも何でも渡せるというわけには行かない。 だから、JAVAやC#でれば namePrintForDog 及び namePrintForCat といった具合にそれぞれ特定のクラスを渡せるメソッドを作成するか、 インターフェース(あるいは抽象化クラス)を利用して受け渡しのクラスを汎用化することで利便性をはかる。これがポリモフィズムってわけだが。
前述のコードを実行してもPHPではなんのことなく動く。 更にいうなら、まったく仕組みの違うクラスを用意してnamePrintメソッドに渡したとしても・・・
//コード2
class dog{
private $name = "";
public function __construct($lname = NULL){
if(!is_null($lname)){
$this->name = $lname;
}//END_if
}//END_Function
public function getName(){
return $this->name;
}//END_Function
public function Iam(){
return get_class($this);
}//END_Function
}//END_Class
class pc{
private $name = "";
public function __construct($lname = NULL){
if(!is_null($lname)){
$this->name = $lname;
}//END_if
}//END_Function
public function getName(){
return "Core2Duo" . $this->name;
}//END_Function
public function Iam(){
return "DELL inc Machine";
}//END_Function
}//END_Class
class printer{
public function __construct(){
}//END_Function
public function namePrint($obj){
echo "I am ".$obj->Iam() ."'s ".$obj->getName() ."
";
}//END_Function
}//END_Class
$d = new dog("ポチ");
$c = new pc("XPS");
//移動クラスを作成
$pt = new printer();
$pt->namePrint($d);
$pt->namePrint($c);
I am dog's ポチ I am DELL inc Machine's Core2DuoXPS・・・動く。上記のようにメソッドの名前さえあっていればいい。 PHPは(他のスクリプトにしても)クラスは配列の延長線上みたいな扱いができる。なので変数の型を気にしないようにクラスの型もあまり気をつかわない。 だからインターフェースとかへの理解が鈍ってしまう、ような気がする。 というか、最初にPHPからプログラムを覚えた人なんかは変数の型とか、なかなか理解できんだろうなーとかって思うけどうどうなんだろう。
さて、そこでPHPでクラス型に配慮した渡し方にコードを変えてみる。 ここではnamePrintできるのはdogクラスのみとしてみる。 といっても「コード1」のnamePrintメソッドの実装を以下のように変えるだけ。
public function namePrint(dog $obj){
echo "I am ".$obj->Iam() ."'s ".$obj->getName() ."
";
}//END_Function
これで渡せるクラスはdogクラスだけだよ、ということになった。これがタイプヒンティングという処理。
試しに実行してみると1行目のドッグは表示されるが、2行目のキャットはエラーで表示されない。
型を認識しているということ。
では、dogもcatも渡したいけど、pcは渡したくないといった場合はどうするのか?
この場合はスーパークラスを指定してあげることでサブクラスであるdogとcatを通して以外のpcを通さないということになる。
class animal{
private $name = "";
public function __construct($lname = NULL){
if(!is_null($lname)){
$this->name = $lname;
}//END_if
}//END_Function
public function getName(){
return $this->name;
}//END_Function
public function Iam(){
return get_class($this);
}//END_Function
}//END_Class
class cat extends animal{
}//END_Class
class dog extends animal{
}//END_Class
class pc{
private $name = "";
public function __construct($lname = NULL){
if(!is_null($lname)){
$this->name = $lname;
}//END_if
}//END_Function
public function getName(){
return "Core2Duo" . $this->name;
}//END_Function
public function Iam(){
return "DELL inc Machine";
}//END_Function
}//END_Class
class printer{
public function __construct(){
}//END_Function
public function namePrint(animal $obj){
echo "I am ".$obj->Iam() ."'s ".$obj->getName() ."
";
}//END_Function
}//END_Class
$d = new dog("ポチ");
$c = new cat("ミケ");
$p = new pc("XPS");
//移動クラスを作成
$pt = new printer();
$pt->namePrint($d);
$pt->namePrint($c);
$pt->namePrint($p);
dogとcatは渡せたけど、pcクラスについてはエラーが出ているはず。
ここではスーパークラスを指定したが、あるいはこれをインターフェースに置き換えてあげてもよい。
2009年 11月 13日ドキュメント作成
2009年 12月 1日ドキュメント更新