特集
2004/05/25 20:30 更新
UNIX USER 2004年6月号「実践! 最新PHP 5」より転載:
Part 2 Zend Engine 2 (2/3)
拡張された機能 |
PHP 5では、オブジェクト指向プログラミングに必要な機能が数多く追加されている。これらは、一度でも手を染めると後戻りできないほど便利なものばかりである。JavaやC++などのオブジェクト指向言語を経験したことのないユーザーも、PHP 5の導入を機にぜひ習得することをお勧めする。
では、どのような機能が実装されたのかを解説しよう。
抽象クラス・メソッド、インターフェイス
PHP 5では、Javaでおなじみの抽象クラス・メソッド※に対応した。抽象クラスを継承する場合は、abstractメソッドをサブクラスで実装する必要がある。実装しなかった場合、Fatalerrorとなるので注意してほしい(リスト5とその結果リスト6)。
リスト5 abstractメソッドをサブクラスで実装 |
1 <?PHP 2 // 抽象クラスの宣言 3 abstract class Foo 4 { 5 // 抽象メソッド 6 // (継承したクラスで実装しなければ 7 // ならないメソッド) 8 abstract public function now(); 9 } 10 11 // 抽象クラスの継承 12 class Bar extends Foo 13 { 14 // 抽象メソッドをオーバーライド(実装) 15 public function now() { 16 return date("Y-m-d H:i:s"); 17 } 18 } 19 20 $obj = new Bar(); 21 echo $obj->now(); 22 23 ?> |
リスト6 abstractメソッドをサブクラスで実装(実行結果) |
2004-04-17 17:56:16 |
また、抽象クラス・メソッドのほかに、インターフェイス※にも対応している。インターフェイスのメリットは、インターフェイス自体を継承することができる点である。抽象クラスと合わせて、自作ライブラリの作成に活用すると良いだろう(リスト7とその結果リスト8)。
リスト7 インターフェイスの使用 |
1 <?PHP 2 // インターフェイスの作成 3 interface Foo 4 { 5 public function now(); 6 } 7 8 // インターフェイスの作成 9 // Fooを継承しているので、FooとFoo2の 10 // 2つのインターフェイスが対象となる 11 interface Foo2 extends Foo { 12 public function yesterday(); 13 } 14 15 // インターフェイスFoo2を実装する 16 class Bar implements Foo2 17 { 18 // Fooで定義されたインターフェイスの実装 19 public function now() { 20 return date("Y-m-d H:i:s"); 21 } 22 23 // Foo2で定義されたインターフェイスの実装 24 public function yesterday() { 25 return date("Y-m-d H:i:s", 26 time() - 86400); 27 } 28 } 29 30 $obj = new Bar(); 31 var_dump($obj->now(),$obj->yesterday()); 32 ?> |
リスト8 インターフェイスの使用(実行結果) |
string(19) "2004-04-17 17:56:58" string(19) "2004-04-16 17:56:58" |
private/protected/public修飾子
PHP 4では、メンバー変数とメソッドの動作がすべてpublicであったため、名前の前にアンダースコアを付けるなどしてpublicとprivateの区別を付ける習慣が存在した。しかし、これは本質的な対策ではない。PHP 5では、このような暗黙の了解事項を設ける必要は一切ない。
PHP5では、Javaなどのオブジェクト指向言語と同様に、明示的に宣言可能である。もちろん、private宣言された変数やメソッドは同一クラス内でしかアクセスは許されず、protected宣言であれば同一クラスまたはサブクラスしかアクセスが許されない。
実際にどのような動作なのか、リスト9のサンプルリストを実行してみよう(リスト10)。
リスト9 private/protected/public修飾子の使用 |
1 <?PHP 2 class Foo 3 { 4 // メンバー変数の宣言 5 public $name; 6 protected $age; 7 private $addr; 8 9 // 引数の値をメンバー変数に代入する 10 function setProfile($name, $age, 11 $addr) { 12 $this->name = $name; 13 $this->age = $age; 14 $this->addr = $addr; 15 } 16 } 17 18 $obj = new Foo(); 19 $obj->setProfile("foo bar", 28, "Tokyo"); 20 21 // $name以外のメンバー変数は表示されない 22 // (public宣言ではないため) 23 var_dump($obj); 24 ?> |
リスト10 private/protected/public修飾子の使用(実行結果) |
object(Foo)#1 (3) { ["name"]=> string(7) "foo bar" } |
このサンプルは、メンバー変数$name、$age、$addrのそれぞれにpublic/protected/private宣言を行っている。public宣言されている$name以外は、クラス内でしか操作できない。また、23行目ではvar_dumpを使って結果をダンプしているが、出力結果には$nameしか表示されない。これも、前述の宣言が影響を与えているためである。
では、privateとprotectedにどのような違いがあるのだろうか。その回答はリスト11のサンプルスクリプトの中にある。リスト9のスクリプトではメンバー変数が対象であったが、このスクリプトはメソッドに対して宣言を行っている(リスト12)。
リスト11 private/protected/public修飾子の効果 |
1 <?PHP 2 class Foo 3 { 4 public $name; 5 6 // サブクラスでしか使えないメソッド 7 protected function setName($name) { 8 $this->name = $name; 9 } 10 } 11 12 class Bar extends Foo 13 { 14 public function setMyName($name) { 15 // スーパークラスのsetName 16 // メソッドを実行 17 parent::setName($name); 18 } 19 } 20 21 $obj = new Bar(); 22 $obj->setMyName("foo bar"); 23 // ↑setMyNameをsetNameに変更すると 24 // エラーになる 25 26 var_dump($obj); 27 ?> |
リスト12 メソッドに対するprivate/protected/public修飾子の効果(実行結果) |
object(Bar)#1 (1) { ["name"]=> string(7) "foo bar" } |
Fooクラスのインスタンスを生成しても、setNameメソッドを使うことはできない。これは、setNameメソッドがprotected宣言されているため、同一クラスまたはサブクラスでしかこのメソッドを使用できないからである。
そこで、リスト11のほうではBarというサブクラスを作成し、setMyNameメソッドの中で、スーパークラスであるFooクラスのsetNameメソッドを実行している。
いままで自由にメンバー変数を操作していた人にとって、メンバー変数やメソッドにアクセス制限を設けるという行為は、面倒なだけで無駄な機能に思えるかもしれないだろう。だが、自分が作成・配布したクラスをすべての人が正しい利用方法で使ってくれるとは限らないのが現実である。
トラブルを未然に防ぐためにも、publicにする必要のないメソッドやメンバー変数は、目的に応じてprivateやprotectedで宣言しておく習慣を身に着けておこう。
このページで出てきた専門用語 |
抽象クラス・メソッド 一部のメソッドだけが実装されているか、実装しなければならないメソッドを定義するために用いられる不完全なクラス。インターフェイスと組み合わせて使用する。 インターフェイス 実装しなければいけないメソッドを定義するためのもの。抽象クラスと似ているが、インターフェイスはあくまでも定義だけであり、実装は行わない。 |
[照井進吾,UNIX USER]
Copyright(C) 2010 SOFTBANK Creative Inc. All Right Reserved.