インターフェイス“インターフェイス(interface)”とは?“インターフェイス(もしくはインタフェース)(interface)”という言葉は、直訳すると“境界面”になります。一般的にこの“境界面”は物(もの)と人の間にあるもので、物が人に対して提供するコミュニケートの手段の事です。相変わらず意味が解かりません。 ある物がある機能を持っていて、その機能を使うかどうかの決定権を人間様に委ねる場合、人間様は物がその機能を持っている事を知っている必要があります。が、その機能がどういった仕組みでその機能を実現しているかまでは知る必要がありません。物は人間様に、自分がある機能を備えているという事実を知らせ、実行手段を提供するだけでいいのです。で、この、物が人間様に機能の存在を知らせると共に提供する実行手段が“インターフェイス”です。人が物の機能を使う時、必要な知識は機能の名前と意味だけです。人は物が提供する“インターフェイス”によって、その物が持つ機能の名前と意味を理解し、その機能を使えるようになります。“インターフェイス”は“機能の名前”といえます。ちなみに、物が“インターフェイス”によって機能の意味を人に知らせる行為(?)を“機能の意味をアフォードする”と言ったりもします。 身近なものだと、テレビのリモコンの操作ボタンが“インターフェイス”です。人間様はボタンの存在と意味を認知さえすればよく、電子工学?を理解していないとチャンネルを変えられないという事態にはなりません。 また、“テレビのリモコン”が“テレビのリモコン”でありうる為には、“テレビのリモコン”として存在するその物体が、“テレビのリモコン”でありうる為の機能を備えていて、同時に、“テレビのリモコン”でありうる為の“インターフェイス”を備えている必要があります。でなければその物体は“テレビのリモコン”であるとは言えません。テレビのチャンネルを換える機能を持たない“テレビのリモコン”はありえません。物には備えるべき機能があり、それを備えていなければ存在が認められません。 物は“インターフェイス”によって、自分が持つ機能の実行手段を提供するだけでなく、自分の状態を知らせたりもします(“バッテリー切れ”の様な)。つまり、人と人が言葉や仕草、表情等で行うように、物と人は“インターフェイス”によってコミュニケーションを行っているわけです。 物は人の様に、余程不良品でもない限り、嘘をついたり暴走したりはしません。が、人の勘違いによって予期せぬ問題が起こる可能性があります。この問題を回避するために、物と人がより正確にコミュニケート出来るように“インターフェイス”を設計しなくてはなりません。便利な機能も大事ですが、それを正確に扱えるような“インターフェイス”も大事なんです。物凄く便利な機能を謳っていても、それを使いこなせる技術が前提では、その機能が無いのと一緒です。操作がややこしくて通話が出来ない携帯電話は、通話機能が無いのと一緒です。なんだそりゃ。つーか話逸れ気味。 「interface(インターフェイス)」と「implements(実装)」“インターフェイス”は“機能の名前”だなんて書きましたが、PHPにおける「インターフェイス」も同様に“機能の名前”です。では“機能の名前”の“機能”って何の事なのか?それはオブジェクトが提供する「パブリック」なメソッドの事です。オブジェクトを扱う時、使用するのはクラス外に公開される「パブリック」なメソッドのみで、「プライベート」又は「プロテクテッド」なメソッドは、オブジェクト内部でのみ使用されるため、その存在を意識する必要はありません。つまり、オブジェクトが提供する「パブリック」なメソッドが、オブジェクトが提供する“機能”です。 更に、オブジェクトはある役目を持っていて、その役目を果たすには“備えているべき機能”を備えている必要があります。つまり、“テレビのリモコン”でありうる為には“テレビのリモコン”でありうる為の“備えているべき機能”を備えていなければならない様に、ある役目を持ったオブジェクトも、そのオブジェクトでありうる為の“備えているべき機能”つまり“備えているべきメソッド”を備えていなければなりません。オブジェクトが“備えているべきメソッド”は1つとは限りません。“備えているべきメソッド”が複数である場合が殆どです。1つでも“備えているべきメソッド”を備えていないと、そのオブジェクトはそのオブジェクトではありえません。全て備えて初めて、そのオブジェクトでありうるのです。 要するに、「インターフェイス」は単なる“機能(メソッド)の名前”ではなく、“備えているべき機能(メソッド)の名前”であり、更に“備えているべきメソッド”は複数から構成されていて、その全てをひっくるめた全体の機能をいいます。“テレビのリモコン”は“テレビのリモコン”という機能を持っているから“テレビのリモコン”でありうるのです。 スクリプトを作り、その中でクラスを定義する時、行き当たりばったりで適当に定義する場合もあれば、ちゃんと仕様を決めてから定義する場合もあると思いますが、仕様を決めてから定義する場合、定義するクラスが何の為のクラスでどのような機能を持っているのか、作り始める前に決定しているはずです。仕様決定の段階では、どのような機能を持つのかだけ決めればよく、構造まで決める必要はありません。逆に、仕様で決めた機能を搭載し忘れたらダメです。
で、具体的にPHPではどのようなものなのか?クラスの定義に近いものですが、こちらは「
「インターフェイス」の定義方法はクラスの定義方法と殆ど同じですが、この「インターフェイス」は「抽象クラス」みたいなもので、これのインスタンスを生成するというものではなく、継承した別のクラスがインスタンスを生成出来ます。が(え?)、「インターフェイス」はクラスの様に「
“継承”と“実装”の違いは、“継承”の場合、基底クラスの「抽象メソッド」の処理部を実装しないと自身も「抽象クラス」になるだけですが、“実装”の場合は、「インターフェイス」に定義されたメソッドを全てオーバーライドして処理部を実装しなくてはなりません。実装漏れがあるとその時点で「
「インターフェイス」が備えるメソッドは全て「パブリック」に宣言しなくてはなりません。それ以外の可視性では「 「インターフェイス」はメンバ変数を持つ事が出来ません(“インターフェイス”の意味を考えれば、処理内部で使われるプロパティを定義する必要が無いのが解かる。「インターフェイス」はクラスの様に“オブジェクトの構造を定義するもの”ではなく、“機能の形態を定義するもの”です)が、クラス定数(「インターフェイス定数」と呼ぶ事にする)は定義することが出来ます。
「インターフェイス定数」は、それを所有する「インターフェイス」があるクラスに実装された場合、身分的(?)にそのクラスで定義されたクラス定数となります。つまり、実装した「インターフェイス」が持つ「インターフェイス定数」と同じ名前のクラス定数を定義出来ません(定数の再定義となって「
“継承”と“実装”は同時に行う事が出来ますが、その場合、「 これまた論よりコード。以下のサンプルと結果をご覧下さい。
(Fatal error:「インターフェイス」ではプロパティを定義出来ない)
(Fatal error:「パブリック」以外の可視性は不可)
(Fatal error:「インターフェイス」で通常のメソッド定義は出来ない)
(Fatal error:「インターフェイス」の実装漏れがある)
(Fatal error:「インターフェイス定数」を「クラス定数」として再定義出来ない)
self::GASU_CONST : HODEGASUKA
parent::GASU_CONST : GASUKA
GASU::GASU_CONST : GASUKA
self::iHODE_CONST : HODENASU
parent::iHODE_CONST : (Fatal error:未定義のクラス定数)
iHODE::iHODE_CONST : HODENASU
例によって、コメントアウトしている所で「
「
「インターフェイス」は、クラスに“継承”ではなく“実装”されます。「 「インターフェイス」とそれを実装したクラスは、継承関係にあるわけではないので、インターフェイス定数を「parent::iHODE_CONST」で参照する事は出来ません。 ある役目を持ったクラスを定義する時、クラスに与えるその役目を果たす為の第一条件は、“クラスが役目を果たす為の機能を備えている事”です(“テレビのリモコン”は“テレビのリモコンとしての機能”を備えているから“テレビのリモコン”でありうる様に)。どうやって各機能を実現するかよりも、役目を果たす為の機能を全て備えている事がまず大事です。具体的な処理部の実装とは別問題として考える為に態々「インターフェイス」を定義します。 ところで、“物と人がより正確にコミュニケート出来るように「インターフェイス」を設計しなくてはならない”なんて書きましたが、PHPにとっての「インターフェイス」はどのように意識して設計すればよいのでしょうか?それは“判り易い名前を付ける事”です(それだけ?)。PHPのビルトインクラスのメソッドや、PEARにて配布されているクラスのメソッドの名前は、「getXxxYyy()」や「setXxxYyy()」、「createXxxYyy()」のように、意味的に共通するメソッド名は共通する接頭辞なんかを付けたりしています。これらのコードを参考にして、メソッドのネーミングを行うと良いです。 インターフェイスの拡張
「インターフェイス」は「
(Fatal error:継承元の「インターフェイス定数」を再定義出来ない) インターフェイス「iHODENASU」に、インターフェイス「iHODE」とインターフェイス「iNASU」を継承させました。結果的に「HODENASU1」クラスと「HODENASU2」クラスは全く同じ構造です。 更に、以下のサンプルと結果をご覧下さい。
Array ( [HODE] => Array ( [iBASE] => iBASE ) [NASU] => Array ( [iSUB] => iSUB [iBASE] => iBASE ) )
「 サンプルの結果を見ると、何れのクラスも「iBASE」インターフェイスを実装しているのが判ります。“ある別の「インターフェイス」を実装したクラス”を継承したクラスも、“ある別の「インターフェイス」を継承した「インターフェイス」”を実装したクラスも、そのクラスは継承元の「インターフェイス」を実装していると見なされます。 オブジェクト引数のインターフェイス指定関数やクラスのメンバ関数の定義時に“オブジェクト引数のクラス指定(「オブジェクト引数のクラス指定」のページで解説)”が出来ますが、同様に「インターフェイス名」も指定することが出来ます。この場合、渡されたオブジェクトが、指定された「インターフェイス」を実装しているか否かがチェックされます。
$obj must be an instance of 'HODENASU'. $obj is an instance of 'APETOPE'. $obj must implement interface 'iHODE'. $obj implements... Array ( [iHODE] => iHODE [iNASU] => iNASU [iHODENASU] => iHODENASU ) (Fatal error:インターフェイス「iNDA」を実装していなければならない)
単純に、渡されたオブジェクトが指定した「インターフェイス」を実装していればOKで、実装していなければ「 定義済みのインターフェイスPHPには予め幾つかの「インターフェイス」が定義されています。 定義済みの「インターフェイス」にはどのようなものがあるのか、下記のスクリプトを実行して見てみます。
Array ( [Traversable] => Array ( ) [IteratorAggregate] => Array ( [0] => getIterator ) [Iterator] => Array ( [0] => current [1] => next [2] => key [3] => valid [4] => rewind ) [ArrayAccess] => Array ( [0] => offsetExists [1] => offsetGet [2] => offsetSet [3] => offsetUnset ) [Reflector] => Array ( [0] => export [1] => __toString ) [RecursiveIterator] => Array ( [0] => hasChildren [1] => getChildren [2] => current [3] => next [4] => key [5] => valid [6] => rewind ) [SeekableIterator] => Array ( [0] => seek [1] => current [2] => next [3] => key [4] => valid [5] => rewind ) ) 定義済みの「インターフェイス」と定義されるメソッド名を出力しました。今の所(PHP5.0.3)この7つが定義されています。 ついでに、定義済みの「インターフェイス」を実装する定義済みクラス名を抽出、出力しました。 今回のサンプルで取得できた、現在定義されている7つの「インターフェイス」は、「イテレーション」と「リフレクション」で扱います。ちなみに、サンプル中の「ReflectionClass」クラスも「リフレクション」で扱います。詳細については各ページで解説します。 作成日:2005年01月13日 最終更新日:2005年01月13日
【通常モード で表示】
|