PHP 5には完全なリフレクション APIが付属しており、 クラス、インターフェイス、関数、メソッド、そしてエクステンションについて リバースエンジニアリングを行うことができます。 さらに、このリフレクション APIは関数、クラス、メソッドに 関するドキュメントコメントも取得することができます。
リフレクション APIは、Zend Engineのオブジェクト指向エクステンション で、以下のクラスから構成されています。
注意:
これらのクラスに関する詳細については、次章を参照してください。
以下の例のコードを実行してみましょう。
例 19-33. リフレクション APIの基本的な使用法
<?php
Reflection
::
export
(new
ReflectionClass
(
'Exception'
));
?>
|
上の例の出力は以下となります。
Class [ <internal> class Exception ] { - Constants [0] { } - Static properties [0] { } - Static methods [0] { } - Properties [6] { Property [ <default> protected $message ] Property [ <default> private $string ] Property [ <default> protected $code ] Property [ <default> protected $file ] Property [ <default> protected $line ] Property [ <default> private $trace ] } - Methods [9] { Method [ <internal> final private method __clone ] { } Method [ <internal> <ctor> public method __construct ] { - Parameters [2] { Parameter #0 [ <required> $message ] Parameter #1 [ <required> $code ] } } Method [ <internal> final public method getMessage ] { } Method [ <internal> final public method getCode ] { } Method [ <internal> final public method getFile ] { } Method [ <internal> final public method getLine ] { } Method [ <internal> final public method getTrace ] { } Method [ <internal> final public method getTraceAsString ] { } Method [ <internal> public method __toString ] { } } }
|
|
ReflectionException
は標準の
Exception
を継承しており、 リフレクション API によって投げられます。 固有のメソッドやプロパティは導入されていません。
ReflectionFunction
クラスにより、 関数のリバースエンジニアリングが可能となります。
注意:
getNumberOfParameters()
と
getNumberOfRequiredParameters()
は PHP 5.0.3 で追加され、
invokeArgs()
は PHP 5.1.0 で追加されました。
関数の内部を調べるために、まず、
ReflectionFunction
クラスのインスタンスを 生成する必要があります。 次にこのインスタンスの上のメソッドのどれかをコールすることができます。
例 19-34.
ReflectionFunction
クラスの使用法
<?php
/**
* 簡単なカウンタ
*
* @return int
*/
function
counter
()
{
static
$c
=
0
;
return
$c
++;
}
// Reflection_Function クラスのインスタンスを生成する
$func
= new
ReflectionFunction
(
'counter'
);
// 基本情報を表示する
printf
(
"===> The %s function '%s'\n"
.
" declared in %s\n"
.
" lines %d to %d\n"
,
$func
->
isInternal
() ?
'internal'
:
'user-defined'
,
$func
->
getName
(),
$func
->
getFileName
(),
$func
->
getStartLine
(),
$func
->
getEndline
()
);
// ドキュメントコメントを表示する
printf
(
"---> Documentation:\n %s\n"
,
var_export
(
$func
->
getDocComment
(),
1
));
// static 変数があれば表示する
if (
$statics
=
$func
->
getStaticVariables
())
{
printf
(
"---> Static variables: %s\n"
,
var_export
(
$statics
,
1
));
}
// 関数を呼び出す
printf
(
"---> Invokation results in: "
);
var_dump
(
$func
->
invoke
());
// export() メソッドを使用する方が良い知れない
echo
"\nReflectionFunction::export() results:\n"
;
echo
ReflectionFunction
::
export
(
'counter'
);
?>
|
|
ReflectionParameter
クラスは、 関数またはメソッドのパラメータに関する情報を取得します。
注意:
getDefaultValue()
,
isDefaultValueAvailable()
,
isOptional()
は PHP 5.0.3 で追加され、
isArray()
は PHP 5.1.0で追加されました。
getDeclaringFunction()
および
getPosition()
は PHP 5.1.3 で追加されました。
関数パラメータの内部を調べる際には、まず、
ReflectionFunction
クラスまたは
ReflectionMethod
クラスのインスタンスを 作成する必要があります。 次に、配列のパラメータを取得するために、そのインスタンスの
getParameters()
メソッドを使用してください。
例 19-35.
ReflectionParameter
クラスの使用
<?php
function
foo
(
$a
,
$b
,
$c
) { }
function
bar
(
Exception $a
, &
$b
,
$c
) { }
function
baz
(
ReflectionFunction $a
,
$b
=
1
,
$c
=
null
) { }
function
abc
() { }
// コマンドラインから与えられたパラメータを使って
// Reflection_Function のインスタンスを生成する
$reflect
= new
ReflectionFunction
(
$argv
[
1
]);
echo
$reflect
;
foreach (
$reflect
->
getParameters
() as
$i
=>
$param
) {
printf
(
"-- Parameter #%d: %s {\n"
.
" Class: %s\n"
.
" Allows NULL: %s\n"
.
" Passed to by reference: %s\n"
.
" Is optional?: %s\n"
.
"}\n"
,
$i
,
$param
->
getName
(),
var_export
(
$param
->
getClass
(),
1
),
var_export
(
$param
->
allowsNull
(),
1
),
var_export
(
$param
->
isPassedByReference
(),
1
),
$param
->
isOptional
() ?
'yes'
:
'no'
);
}
?>
|
|
ReflectionClass
クラスにより、 クラスのリバースエンジニアリングが可能となります。
注意:
hasConstant()
,
hasMethod()
,
hasProperty()
,
getStaticPropertyValue()
および
setStaticPropertyValue()
は、PHP 5.1.0 で追加されました。 また、
newInstanceArgs()
は PHP 5.1.3 で追加されました。
クラスのイントロスペクションを行うには、まず
ReflectionClass
クラスのインスタンスを生成する必要があります。それから、 このインスタンスのメソッドをコールしてください。
例 19-36.
ReflectionClass
クラスの使用法
<?php
interface Serializable
{
// ...
}
class
Object
{
// ...
}
/**
* カウンタクラス
*/
class
Counter
extends
Object implements Serializable
{
const
START
=
0
;
private
static
$c
=
Counter
::
START
;
/**
* カウンタを呼び出す
*
* @access public
* @return int
*/
public
function
count
() {
return
self
::
$c
++;
}
}
// ReflectionClass クラスのインスタンスを生成する
$class
= new
ReflectionClass
(
'Counter'
);
// 基本情報を表示する
printf
(
"===> The %s%s%s %s '%s' [extends %s]\n"
.
" declared in %s\n"
.
" lines %d to %d\n"
.
" having the modifiers %d [%s]\n"
,
$class
->
isInternal
() ?
'internal'
:
'user-defined'
,
$class
->
isAbstract
() ?
' abstract'
:
''
,
$class
->
isFinal
() ?
' final'
:
''
,
$class
->
isInterface
() ?
'interface'
:
'class'
,
$class
->
getName
(),
var_export
(
$class
->
getParentClass
(),
1
),
$class
->
getFileName
(),
$class
->
getStartLine
(),
$class
->
getEndline
(),
$class
->
getModifiers
(),
implode
(
' '
,
Reflection
::
getModifierNames
(
$class
->
getModifiers
()))
);
// ドキュメントコメントを表示する
printf
(
"---> Documentation:\n %s\n"
,
var_export
(
$class
->
getDocComment
(),
1
));
// このクラスが実装しているインターフェースを表示する
printf
(
"---> Implements:\n %s\n"
,
var_export
(
$class
->
getInterfaces
(),
1
));
// クラス定数を表示する
printf
(
"---> Constants: %s\n"
,
var_export
(
$class
->
getConstants
(),
1
));
// クラスプロパティを表示する
printf
(
"---> Properties: %s\n"
,
var_export
(
$class
->
getProperties
(),
1
));
// クラスメソッドを表示する
printf
(
"---> Methods: %s\n"
,
var_export
(
$class
->
getMethods
(),
1
));
// このクラスがインスタンス化可能な場合、インスタンスを生成する
if (
$class
->
isInstantiable
()) {
$counter
=
$class
->
newInstance
();
echo
'---> $counter is instance? '
;
echo
$class
->
isInstance
(
$counter
) ?
'yes'
:
'no'
;
echo
"\n---> new Object() is instance? "
;
echo
$class
->
isInstance
(new
Object
()) ?
'yes'
:
'no'
;
}
?>
|
|
注意:
$class = new ReflectionClass('Foo'); $class->isInstance($arg)
は、
$arg instanceof Foo
または
is_a($arg, 'Foo')
と等価です。
ReflectionObject
クラスにより、 オブジェクトのリバースエンジニアリングが可能となります。
ReflectionMethod
クラスにより、 クラスメソッドのリバースエンジニアリングが可能となります。
メソッドの内部を調べるために、まず、
ReflectionMethod
クラスのインスタンスを 生成する必要があります。 次にこのインスタンスの上のメソッドのどれかをコールすることができます。
例 19-37.
ReflectionMethod
クラスの使用
<?php
class
Counter
{
private
static
$c
=
0
;
/**
* カウンタをインクリメントする
*
* @final
* @static
* @access public
* @return int
*/
final public
static function
increment
()
{
return ++
self
::
$c
;
}
}
// Reflection_Method クラスのインスタンスを生成する
$method
= new
ReflectionMethod
(
'Counter'
,
'increment'
);
// 基本情報を表示する
printf
(
"===> The %s%s%s%s%s%s%s method '%s' (which is %s)\n"
.
" declared in %s\n"
.
" lines %d to %d\n"
.
" having the modifiers %d[%s]\n"
,
$method
->
isInternal
() ?
'internal'
:
'user-defined'
,
$method
->
isAbstract
() ?
' abstract'
:
''
,
$method
->
isFinal
() ?
' final'
:
''
,
$method
->
isPublic
() ?
' public'
:
''
,
$method
->
isPrivate
() ?
' private'
:
''
,
$method
->
isProtected
() ?
' protected'
:
''
,
$method
->
isStatic
() ?
' static'
:
''
,
$method
->
getName
(),
$method
->
isConstructor
() ?
'the constructor'
:
'a regular method'
,
$method
->
getFileName
(),
$method
->
getStartLine
(),
$method
->
getEndline
(),
$method
->
getModifiers
(),
implode
(
' '
,
Reflection
::
getModifierNames
(
$method
->
getModifiers
()))
);
// ドキュメントコメントを表示する
printf
(
"---> Documentation:\n %s\n"
,
var_export
(
$method
->
getDocComment
(),
1
));
// static 変数があれば表示する
if (
$statics
=
$method
->
getStaticVariables
()) {
printf
(
"---> Static variables: %s\n"
,
var_export
(
$statics
,
1
));
}
// メソッドを呼び出す
printf
(
"---> Invokation results in: "
);
var_dump
(
$method
->
invoke
(
NULL
));
?>
|
|
注意:
private, protectedまたはabstractメソッドのinvokeを行うと、
invoke()
から例外がスローされます。
注意:
上記のstaticメソッドの場合、
invoke()
の最初の引数にNULLを渡す必要があります。 staticでないメソッドの場合、ここにクラスのインスタンスを指定してください。
ReflectionProperty
クラスにより、 クラスプロパティに関する リバースエンジニアリングが可能となります。
プロパティの内部を調べるために、まず、
ReflectionProperty
クラスのインスタンスを 生成する必要があります。 次にこのインスタンスの上のメソッドのどれかをコールすることができます。
例 19-38.
ReflectionProperty
クラスの使用
<?php
class
String
{
public $length
=
5
;
}
// ReflectionProperty クラスのインスタンスを生成する
$prop
= new
ReflectionProperty
(
'String'
,
'length'
);
// 基本情報を表示する
printf
(
"===> The%s%s%s%s property '%s' (which was %s)\n"
.
" having the modifiers %s\n"
,
$prop
->
isPublic
() ?
' public'
:
''
,
$prop
->
isPrivate
() ?
' private'
:
''
,
$prop
->
isProtected
() ?
' protected'
:
''
,
$prop
->
isStatic
() ?
' static'
:
''
,
$prop
->
getName
(),
$prop
->
isDefault
() ?
'declared at compile-time'
:
'created at run-time'
,
var_export
(
Reflection
::
getModifierNames
(
$prop
->
getModifiers
()),
1
)
);
// String のインスタンスを生成する
$obj
= new
String
();
// 現在の値を取得する
printf
(
"---> Value is: "
);
var_dump
(
$prop
->
getValue
(
$obj
));
// 値を変更する
$prop
->
setValue
(
$obj
,
10
);
printf
(
"---> Setting value to 10, new value is: "
);
var_dump
(
$prop
->
getValue
(
$obj
));
// オブジェクトをダンプする
var_dump
(
$obj
);
?>
|
|
注意:
privateまたはprotectedクラスプロパティの値の取得または設定を 行うと、例外がスローされます。
The
ReflectionExtension
クラスにより、 エクステンションのリバースエンジニアリングが可能となります。 実行時にロードされている全てのエクステンションを
get_loaded_extensions()
により取得することができます。
メソッドの内部を調べるために、まず、
ReflectionExtension
クラスのインスタンスを 生成する必要があります。 次にこのインスタンスの上のメソッドのどれかをコールすることができます。
例 19-39.
ReflectionExtension
クラスの使用
<?php
// ReflectionProperty クラスのインスタンスを生成する
$ext
= new
ReflectionExtension
(
'standard'
);
// 基本情報を表示する
printf
(
"Name : %s\n"
.
"Version : %s\n"
.
"Functions : [%d] %s\n"
.
"Constants : [%d] %s\n"
.
"INI entries : [%d] %s\n"
.
"Classes : [%d] %s\n"
,
$ext
->
getName
(),
$ext
->
getVersion
() ?
$ext
->
getVersion
() :
'NO_VERSION'
,
sizeof
(
$ext
->
getFunctions
()),
var_export
(
$ext
->
getFunctions
(),
1
),
sizeof
(
$ext
->
getConstants
()),
var_export
(
$ext
->
getConstants
(),
1
),
sizeof
(
$ext
->
getINIEntries
()),
var_export
(
$ext
->
getINIEntries
(),
1
),
sizeof
(
$ext
->
getClassNames
()),
var_export
(
$ext
->
getClassNames
(),
1
)
);
?>
|
|
組み込みクラスの特別なバージョンを作成したい場合 (例えば、、エクスポートする際に、色づけしたHTMLを作成したり、 メソッドの代わりに簡単にアクセスできるメンバー変数を作成したり、 補助的なメソッドを作成したり、)、 Reflectionクラスを拡張することができます。
例 19-40. 組み込みクラスを拡張する
<?php
/**
* 独自の Reflection_Method クラス
*/
class
My_Reflection_Method
extends
ReflectionMethod
{
public $visibility
=
''
;
public
function
__construct
(
$o
,
$m
)
{
parent
::
__construct
(
$o
,
$m
);
$this
->
visibility
=
Reflection
::
getModifierNames
(
$this
->
getModifiers
());
}
}
/**
* デモクラス #1
*
*/
class
T
{
protected
function
x
() {}
}
/**
* デモクラス #2
*
*/
class
U
extends
T
{
function
x
() {}
}
// 基本情報を表示する
var_dump
(new
My_Reflection_Method
(
'U'
,
'x'
));
?>
|
|
注意:
注意: Iコンストラクタを上書きした場合、 挿入するコードの前に 親クラスのコンストラクタをコールしわすれないようにしてください。 これを怠ると、以下のようなエラーを発生します。
Fatal error: Internal error: Failed to retrieve the reflection object