ORJavaScriptが有効ではありません。リフレクションリフレクションPHP5になって、「リバースエンジニアリング(ここでは“スクリプトを解析する行為”を指す)」を行う為の機能、「リフレクション」が搭載されました。「リフレクション」によって、関数やクラス、メソッド等を解析する事が出来ます。指定したクラスの構造(継承するクラス名や実装するインターフェイス名、備えるプロパティやメソッド等に関する情報)の出力、指定したインターフェイスを実装するか等のチェック、備えるメソッド名等の取得が行えます。リフレクタ/「Reflector」インターフェイス/「Reflection」クラススクリプトの解析は、関数なら関数用に、クラスならクラス用に定義されたクラス、各種用「リフレクタ」を使用して行います。「リフレクション」に関係するインターフェイス・クラスは、以下のような継承関係で定義されています。ReflectionExtension(拡張モジュール用「リフレクタ」)上記1つのインターフェイスと9つのクラスが定義されていています。「Reflector」インターフェイスを実装する7つのクラス(「Reflection*」クラス)が「リフレクタ」で、「Reflection」クラスは「リフレクタ」の補助用に定義されるクラス、「ReflectionException」クラスは「リフレクション用例外」(「リフレクタ」が投げる例外)です。スクリプト(クラスや関数)の解析は各種用「リフレクタ」を使用して行います。あるクラスを解析する場合はクラス用「リフレクタ」を使用し、メソッドを解析する場合はメソッド用「リフレクタ」を使用します。「リフレクタ」の元となる「Reflector」インターフェイスは下表に記した2つの抽象メソッドを備えます。全ての「リフレクタ」は最低この2つのメソッドを備えます。各々の情報を出力する。string各「リフレクタ」は、この2つの他に各々のメソッドを追加で備えます。「export()」メソッドは実装時に1〜2つの(解析対象の名前を指定する為の)引数が追加されます(各「リフレクタ」が備えるコンストラクタと同じ形態になります)。「リフレクタ」の補助用に定義される「Reflection」は下表に記した2つのメソッドを備えます。「修飾値」を元に修飾子を格納した配列を返す。「修飾値」は「getModifiers()」メソッド(「リフレクタ」が備えていれば)によって得られます。array「リフレクション」には「リフレクタ」を使用しますが、補助的に「Reflection」クラスが備える2つのクラスメソッドを使用します。これまた論よりコード。以下のサンプルと結果をご覧下さい。error:このオブジェクトのクローンは生成出来ない)例によって、コメントアウトしている所で「E_ERROR」エラーが発生します。これが基本的な使い方です。「リフレクタ」及び補助用に定義される「Reflection」クラスが備える「export()」メソッドを使用して各種の情報を出力させます。「export()」メソッドが出力する内容にはタグで括られた部分があり、そのままだとブラウザで見た時にタグで括られた部分が表示されないので、出力制御関数(「ob_start()」関数と「ob_get_clean()」関数)を使用して対処しています。「リフレクタ」が備える方の「export()」メソッドを使用する場合は、“解析対象となるもの(クラスや関数等)の名前もしくはオブジェクト”を引数に指定し、「Reflection」クラスが備える方の「export()」メソッドを使用する場合は、“解析対象を指定して生成した「リフレクタ」オブジェクト”を引数に指定します。何れも出力結果は同じです。見ての通り、“「リフレクタ」が備える方の「export()」メソッドをコールする時に渡す引数”と、「リフレクタ」オブジェクトを生成する時に渡す引数つまり“「リフレクタ」のコンストラクタに渡す引数”は同じです。今回のサンプルでは、適当に定義した関数を、関数用「リフレクタ」を使用して解析しました。「ReflectionFunction::export("hode_func");」の部分で、適当に定義した関数の名前を引数に「ReflectionFunction」クラス(関数用「リフレクタ」)の「export()」メソッドをコールすると、指定した関数に関する情報が出力されました。ReflectionFunction("hode_func");」の部分で関数用「リフレクタ」オブジェクトを生成し、「Reflection::export($func_reflector);」の部分で生成した関数用「リフレクタ」オブジェクトを引数に「Reflection」クラス(「リフレクション」補助用クラス)の「export()」メソッドをコールしていますが、結果は「ReflectionFunction::export("hode_func");」の場合と全く同じです。状況に応じて使い分けます。「リフレクタ」オブジェクトを文字列として出力しようとすると、特殊メソッド「__toString()」メソッドがコールされ、その返り値が出力されました。これまた「export()」メソッドを使用した場合と結果が全く同じです。「リフレクタ」オブジェクトが備える各種メソッドをコールして、色々な情報を得たり色々出来ます。全ての「リフレクタ」は、解析対象の名前が格納された「プロパティ$name」を備えます。このプロパティの値を取得する為の「getName()」メソッドを備えますが、「プロパティ$name」は「パブリック」に宣言されているのでクラス外から直接参照する事も出来ます。「リフレクタ」オブジェクトのクローンを生成しようとすると、「E_ERROR」エラーを発します。要するに、「リフレクタ」オブジェクトのクローンは生成出来ません。ちなみに、その他の「リフレクタ」の場合も同様にクローンは生成出来ません。__clone()」で定義しています。これだとクローンを生成しようとした時に可視性を指摘するエラーを発するはずですが、何故か「クローンが生成出来ないオブジェクト」だというエラーを発します。「Reflection」クラスが備えるもう1つのメソッド、「getModifierNames()」メソッドは、クラスやメソッドの定義時に指定された修飾子(「final」や「public」等)を配列に格納して返す関数です。「リフレクタ」が「getModifiers()」メソッドを備えている場合、このメソッドは、解析対象の例えばクラスの“定義時に指定された修飾子の組み合わせを表す整数値”を返します。このメソッドの返り値を引数に「Reflection::getModifierNames()」メソッドをコールします。以下のサンプルと結果をご覧下さい。static)今回のサンプルでは、適当に定義したメソッドを、メソッド用「リフレクタ」を使用して解析しました。メソッド用「リフレクタ」オブジェクトを生成し、「リフレクタ」が備える「getModifiers()」メソッドで、“解析対象のメソッドが定義時に指定された修飾子の組み合わせを表す整数値”を取得、この値を引数に「Reflection::getModifierNames()」をコールすると、修飾子を格納した配列を得る事が出来ました。ちなみに、「getModifiers()」メソッドで得られる値は、“「ファイナル」宣言したら「4」加算”、“「アブストラクト」宣言したら「2」加算”、“「プロテクテッド」は「パブリック」に「256」加算”、“「プライベート」は「プロテクテッド」に「512」加算”といった感じの定数です。こんな感じで、解析対象によって各種用「リフレクタ」を使用して解析を行い、補助的に「Reflection」クラスのメソッドを使用します。リフレクション用例外/「ReflectionException」クラス「リフレクション用例外」として「ReflectionException」クラスが定義されています。各種「リフレクタ」及び補助用「Reflection」クラスのメソッドは、問題発生時(指定した解析対象が存在しない場合等)にリフレクション用例外オブジェクトを投げます。以下にサンプルと結果のみ。existdocコメント「リフレクタ」には、スクリプト中の「docコメント」を取得するメソッドを備えるものもあります。この「docコメント」は簡単に言うと“「/**(スラッシュの後に2つのアステリスク)」と「*/」に囲まれたコメント”です。「関数用リフレクタ」等が備える「getDocComment()」は、所定の位置(「関数用リフレクタ」の場合は、解析対象の関数定義の直前)に記述された「docコメント」を取得する事が出来ます。以下のサンプルと結果をご覧下さい。---結果を見ると、通常のコメントは抽出されず、解析対象の定義直前に記述した「docコメント」のみ抽出され、出力されています。関数用リフレクタ/「ReflectionFunction」クラス「関数用リフレクタ」として定義される「ReflectionFunction」クラスは下表に記したメソッドを提供します。定義直前に記述された「docコメント」を返す。指定が必須の(デフォルト値がセットされない)引数の数を返す以下のサンプルと結果をご覧下さい。Array()***************************************結果を見ると、ビルトイン関数を解析した場合に、引数に関する情報が正確に出力されていません。「str_replace()」関数では出力されていますが、「str_pad()」関数では引数があるはずなのに出力されませんでした。“ビルトイン関数を解析した場合、引数に関する情報が正確に得られるものとそうでないものがある”ようです。「関数用リフレクタ」が持つ「getParameters()」メソッドは、解析対象の関数が持つ各引数を解析対象に「引数用リフレクタ」オブジェクトを生成し、生成した各オブジェクトへのリファレンスを格納した配列を返します。このメソッドが返す配列の各要素は「引数用リフレクタ」へのリファレンスなので、その「リフレクタ」が備えるメソッドを使用してそのまま引数を解析する事が出来ます。「getStaticVariables()」メソッドで静的変数を取得しようとした時、静的変数の定義時に配列をセットし、さらにその関数が解析前に一度もコールされていない場合にサーバがダウンしてしまいます。メソッド用リフレクタ/「ReflectionMethod」クラス「メソッド用リフレクタ」として定義される「ReflectionMethod」クラスは、「ReflectionFunction」クラスが提供するメソッドに加えて下表に記したメソッドを提供します。解析対象のメソッドを(「引数」を渡して)コールする。コール可能なのは「スタティック」で「パブリック」なメソッドのみ。クラス名::メソッド名」というメッセージと共に「リフレクション用例外」を投げる以下のサンプルと結果をご覧下さい。static***********************************************解析対象の指定は、第一引数にクラス名もしくはオブジェクトを、第二引数にメソッド名を指定します。オブジェクトを指定した場合はそのクラス名が解析対象となり、結局クラス名を指定した場合と同じです。「メソッド用リフレクタ」は「関数用リフレクタ」を継承しているので、「関数用リフレクタ」が提供するメソッドも使用出来ます。(関数・メソッドの)引数用リフレクタ/「ReflectionParameter」クラス「(関数・メソッドの)引数用リフレクタ」として定義される「ReflectionParameter」クラスは下表に記したメソッドを提供します。引数にクラス名を指定している場合に、そのクラスを解析対象に生成した「クラス・インターフェイス用リフレクタ(ReflectionClass)」オブジェクトを返す。引数に「NULL」が渡される事を許可するか(クラス名が指定された引数には必ず指定したクラスのオブジェクトを渡さなければならず、それ以外の値を渡すと「E_ERROR」エラーを発する。引数に設定されたデフォルト値を返す。optional」というメッセージと共に「リフレクション用例外」を投げる以下のサンプルと結果をご覧下さい。reference*******************************************************関数の引数を解析する場合は関数名と引数名を指定して個別に解析する事が出来ますが、メソッドの引数は指定出来ず、個別の解析が出来ません。メソッドの引数を解析する場合は、まず「メソッド用リフレクタ」を生成し、「関数用/メソッド用リフレクタ」が提供する「getParameters()」メソッドが生成する「引数用リフレクタ」を使用します。引数の解析を個別に解析するよりもまとめて解析する方が自然だと思うので、関数の場合もメソッドの場合も「関数用/メソッド用リフレクタ」の「getParameters()」メソッド経由で解析を行います。クラス・インターフェイス用リフレクタ/「ReflectionClass」クラス「クラス・インターフェイス用リフレクタ」として定義される「ReflectionClass」クラスは下表に記したメソッドを提供します。インスタンスを生成できるか否かを真偽値で返す・・・のかと思いきや、クラスであるか否かを真偽値で返す(抽象クラスの場合でも「TRUE」を返す」)。定義直前に記述された「docコメント」を返す。コンストラクタを解析対象に生成した「メソッド用リフレクタ(ReflectionMethod)」オブジェクトを返す。指定した「メソッド名」を解析対象に生成した「メソッド用リフレクタ(ReflectionMethod)」オブジェクトを返す。指定した「プロパティ名」を解析対象に生成した「プロパティ用リフレクタ(ReflectionProperty)」オブジェクトを返す。指定した「定数名」の値を返す。指定した「オブジェクト」がこのクラスのインスタンスであるか否かを真偽値で返す。インスタンスを生成して返す。基底クラスを解析対象に生成した「クラス・インターフェイス用リフレクタ(ReflectionClass)」オブジェクトを返す。クラスプロパティの名前を添え字に、値を要素にセットした配列を返す。返される配列の添え字には、「パブリック」ならそのまま、「プロテクテッド」なら接頭辞「*(アステリスク)」を付けたプロパティ名が、「プライベート」なら接頭辞として“定義しているクラス名”を付けたプロパティ名がセットされる。プロパティの名前を添え字に、値を要素にセットした配列を返す。拡張モジュールで定義されている場合に、その拡張モジュールを解析対象に生成した「拡張モジュール用リフレクタ(ReflectionExtension)」オブジェクトを返す。拡張モジュールで定義されている場合はその拡張モジュール名を、ユーザー定義である場合は「FALSE」を返す以下のサンプルと結果をご覧下さい。HODE**************************************「クラス・インターフェイス用リフレクタ」で、インターフェイスとクラスの解析が行えます。「クラス・インターフェイス用リフレクタ」は、クラス・インターフェイスが備えるプロパティやメソッド、クラスが実装するインターフェイス等を解析対象に各種用リフレクタを生成するメソッド等を提供するので、それを利用してプロパティ等の解析を行えます。オブジェクト用リフレクタ/「ReflectionObject」クラス「オブジェクト用リフレクタ」として定義される「ReflectionObject」クラスは、「ReflectionClass」クラスが提供するメソッドに加えて下表に記したメソッドを提供します。「オブジェクト」のクラス名を「プロパティ$name」にセットする以下のサンプルと結果をご覧下さい。iterateable*************************************************************「オブジェクト用リフレクタ」は解析対象にオブジェクトを指定する事以外「クラス・インターフェイス用リフレクタ」と殆ど同じです。properties」なる項目が追加されています。これは、オブジェクト生成後に動的に生成されたプロパティ(クラス定義の時点で定義されたプロパティではなく)です。プロパティ用リフレクタ/「ReflectionProperty」クラス「プロパティ用リフレクタ」として定義される「ReflectionProperty」クラスは下表に記したメソッドを提供します。引数に「クラス名」を指定した場合はそれを、「オブジェクト」を指定した場合は指定した「プロパティ名」が定義されているクラスの名前を「プロパティ$class」にセットし、「プロパティ名」を「プロパティ$name」にセットする。指定した「オブジェクト」が解析対象と同じ名前のプロパティを備えている場合に、その「オブジェクト」が備えるプロパティの値を返す。指定した「オブジェクト」が解析対象と同じ名前のプロパティを備えている場合に、その「オブジェクト」が備えるプロパティに指定した「値」をセットする。プロパティが定義されているクラスを解析対象に生成した「クラス・インターフェイス用リフレクタ(ReflectionClass)」オブジェクトを返す以下のサンプルと結果をご覧下さい。HODENASU!!!*******************************************「メソッド用リフレクタ」ではアクセス不可なメソッドも解析出来ましたが、「プロパティ用リフレクタ」では出来ず「未定義だ」という例外を投げます。アクセス可能なプロパティでも、「パブリック」以外の可視性に宣言されたプロパティの名前は「リフレクタ」オブジェクトの「プロパティ$name」にセットされません。結果を見ると、「リフレクタ」オブジェクトの「プロパティ$class」には、「リフレクタ」オブジェクトの生成時に指定したクラスの名前ではなく、解析対象が定義されているクラスの名前がセットされています(「メソッド用リフレクタ」では指定したクラスの名前がセットされます)。「getValue()」メソッドと「setValue()」メソッドは、コール時の引数にオブジェクトを渡します。渡したオブジェクトが解析対象と同じ名前のプロパティを備えている場合に、その「オブジェクト」が備えるプロパティの値を取得/セットします。「パブリック」以外の可視性である場合やプロパティが存在しない場合には「E_ERROR」エラーを発します。拡張モジュール用リフレクタ/「ReflectionExtension」クラス「拡張モジュール用リフレクタ」として定義される「ReflectionExtension」クラスは下表に記したメソッドを提供します。モジュールのバージョン情報があれば返します。定義する全てのクラス・インターフェイスの名前を格納した配列を返す以下のサンプルと結果をご覧下さい。SJIS「拡張モジュール用リフレクタ」ではインストールされて有効な拡張モジュールを解析して、定義されたクラスや関数等を調べる事が出来ます。