PHP中的反射
阿新 • • 發佈:2018-12-04
面向物件編輯中物件被賦予了自省的能力,而這個自省的過程就是反射.
反射,直觀理解應時根據到達地找出出發地和來源.比方說,我給你一個光禿禿的物件,我可以僅僅通過這個物件就能知道它所屬的類,擁有哪些方法. 反射指在PHP執行狀態中,擴充套件分析PHP程式,匯出或提取出關於類,方法,屬性,引數等詳細資訊,包括註釋.這種動態獲取資訊以及動態呼叫物件方法的功能稱為反射API如何使用反射API
以下面程式碼為例1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
class
HandsonBoy
{
public
$name
=
'chenqionghe'
;
public
$age
= 18;
public
function
__set(
$name
,
$value
)
{
echo
'您正在設定私有屬性'
.
$name
.
'<br >值為'
.
$value
.
'<br>'
;
$this
->
$name
=
$value
;
}
public
function
__get(
$name
)
{
if
(!isset(
$this
->
$name
))
{
echo
'未設定'
.
$name
;
$this
->
$name
=
"正在為你設定預設值"
.
'<br>'
;
}
return
$this
->
$name
;
}
}
$boy
=
new
HandsonBoy();
echo
$boy
->name.
'<br />'
;
$boy
->hair =
'short'
;
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$reflect
=
new
ReflectionObject(
$boy
);
$props
=
$reflect
->getProperties();
//獲取屬性的名字
foreach
(
$props
as
$prop
)
{
print
$prop
->getName().PHP_EOL;
}
//獲取物件方法列表
$methos
=
$reflect
->getMethods();
foreach
(
$methos
as
$method
)
{
print
$method
->getName().PHP_EOL;
}
|
也可以不用反射API,使用class函式,返回物件屬性的關聯陣列以及更多的資訊:(針對於公開的屬性和):
1 2 3 4 5 6 |
//返回物件屬性的關聯陣列
var_dump(get_object_vars(
$boy
));
//類屬性
var_dump(get_class_vars(get_class(
$boy
)));
//返回由類的屬性的方法名組成的陣列
var_dump(get_class_methods(get_class(
$boy
)));
|
反射API的功能顯然更強大,甚至能還原這個類的原型,包括方法的訪問許可權,以下簡單封裝了一個列印類的程式碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
/**
* @param $classObject 物件或者類名
*/
function
getClass(
$classObject
)
{
$object
=
new
ReflectionClass(
$classObject
);
$className
=
$object
->getName();
$Methods
=
$Properties
=
array
();
foreach
(
$object
->getProperties()
as
$v
)
{
$Properties
[
$v
->getName()] =
$v
;
}
foreach
(
$object
->getMethods()
as
$v
)
{
$Methods
[
$v
->getName()] =
$v
;
}
echo
"class {$className}\n{\n"
;
is_array
(
$Properties
) && ksort(
$Properties
);
foreach
(
$Properties
as
$k
=>
$v
)
{
echo
"\t"
;
echo
$v
->isPublic() ?
'public'
:
''
,
$v
->isPrivate() ?
'private'
:
''
,
$v
->isProtected() ?
'protected'
:
''
;
$v
->isStatic() ?
'static'
:
''
;
echo
"\t{$k}\n"
;
}
echo
"\n"
;
if
(
is_array
(
$Methods
)) ksort(
$Methods
);
foreach
(
$Methods
as
$k
=>
$v
)
{
echo
"\tfunction {$k}()\n"
;
}
echo
"}\n"
;
}
|
不僅如此,PHP手冊中關於反射API更是有幾十個,可以說,反射完整地描述了一個類或者物件的原型.反射不僅可以用於類和物件,還可以用於函式,擴充套件模組,異常等.
反射有什麼作用
反射可以用於文件生成,因此可以用它對檔案裡的類進行掃描,逐個生成描述文件. 既然反射可以探知類內部結構, 那麼是不是 可以用它做hook實現外掛功能呢?或者是作動態代理呢?拋磚引玉,以下程式碼是個簡單的例子1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
<?php
class
mysql
{
function
connect(
$db
)
{
echo
"連線到資料庫{$db[0]}"
.PHP_EOL;
}
}
class
sqlproxy
{
private
$target
;
public
function
__construct(
$tar
)
{
$this
->target[] =
new
$tar
;
}
public
function
__call(
$name
,
$args
)
{
foreach
(
$this
->target
as
$obj
)
{
$r
=
new
ReflectionClass(
$obj
);
if
(
$method
=
$r
->getMethod(
$name
))
{
if
(
$method
->isPublic() && !
$method
->isAbstract())
{
echo
"方法前攔截記錄LOG"
.PHP_EOL;
$method
->invoke(
$obj
,
$args
);
echo
"方法後攔截"
.PHP_EOL;
}
}
}
}
}
$obj
=
new
sqlproxy(
'mysql'
);
$obj
->connect(
'chenqionghe'
);
|