PHP 自省

本文最后更新于:2024年3月18日 凌晨

PHP 自省

  • 自省(introspection)是一种让程序检查对象特性的机制,可以检查对象的名称,父类(如果存在),属性和访问等,利用自省,你可以编写对任何类或对象进行操作的代码,在编写代码时你不需要知道类中定义了哪些属性和方法,相反,你可以在运行时得到那些信息,这使得你可以写出通用的调试器(debugger),串行化器(serializer)和解剖器(profiler)等,本节将介绍PHP提供的自省功能。

类检验

  • 可以调用class_exists()函数来确定一个类是否存在,该函数有一个字符串参数并返回一个布尔值(true或false),同样,也可以使用get_declared_classes()函数,该函数返回一个包含所有已定义的类的数组,并检查类名是否存在于函数中:
1
2
$yes_no = class_exists(classname);
$classes = get_declared_classes();
  • 你可以通过函数get_class_methods()get_class_vars()来得到一个类中的所有的属性和方法(包括从父类中继承的方法和属性),这些函数的参数为类名,返回值为一个数组:
1
2
$methods = get_class_methods(classname);
$properties = get_class_vars(classname);
  • 类名,可以是一个不带引号的单词,也可以是个带引号的字符串,或者一个包含类名的变量:
1
2
3
4
$class = 'Person';
$methods = get_class_methods($class);
$methods = get_class_methods(Person);// 同上。
$methods = get_class_methods('Person');// 同上。
  • get_class_methods()返回的数组只是简单地列出了方法的名称,而get_class_vars()函数返回的数组中,键名为属性的名称,值为属性的值,该数组中也包含了继承自父类的属性。

提示

  • get_class_vars()函数的一个不足之处是仅返回拥有默认值的属性,而不返回未初始化的属性。
  • 调用get_parent_class()可得到一个类的父类的名称:
1
$superclass = get_parent_class(classname);

示例6-1:显示所有已经声明的类及其信息。

  • 函数display_classes()用来显示所有当前已声明的类,以及它们的方法和属性。
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
function display_classes(){
$classes = get_declared_classes();
foreach($classes as $class){
echo "Showing information about $class<br/>";

echo "$class methods:<br/>";
$methods = get_class_methods($class);
if(!count($methods)){
echo"<i>None</i><br/>";
}
else{
foreach($methods as $method){
echo"<b>$method</b>()<br/>";
}
}
echo "$class properties:<br/>";
$properties = get_class_vars($class);
if(!count($properties)){
echo"<i>None</i><br/>";
}
else{
foreach(array_keys($properties) as $property){
echo "<b>\$$property</b><br/>";
}
}
echo "<hr/>";
}
}

对象检验

  • 如果想知道某个对象所属的类,可先调用is_object()函数来确认它是一个对象,然后调用get_class()函数来得到它所属的类:
1
2
$yes_no = is_object(var);
$classname = get_class(object);
  • 在调用对象的方法之前,可用method_exists()函数来确认该方法是否存在:
1
$yes_no = method_exists(object,method);
  • 调用一个未定义的类方法会触发一个运行期的异常(exception)
  • 就像get_class_vars()返回类的属性数组一样,get_object_vars()返回一个对象的属性数组:
1
array = get_object_vars(object);
  • 同样就像get_class_vars()只返回有默认值的属性,get_object_vars()也只返回有默认值的属性:
1
2
3
4
5
6
7
class Person{
var $name;
var $age;
}
$fred = new Person;
$fred->name = 'Fred';
$props = get_object_vars($fred);//$props为array('name'=>'Fred');
  • 函数get_parent_class()的参数可以是类名或对象名,返回值为父类名,如没有父类,则返回FALSE:
1
2
3
4
5
class A{}
class B extends A{}
$obj = new B;
echo get_parent_class($obj);// 输出A
echo get_parent_class(B);// 输出A

自省程序示例

示例6-2:对象自省函数。

  • 将一个对象的属性,方法和继承数(inheritance tree)信息显示在一个页面中。
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// 返回一个可调用方法的数组(包括继承的方法)
function get_methods($object){
$methods = get_class_methods(get_class($object));

if(get_parent_class($object)){
$parent_methods = get_class_methods(get_parent_class($object));
$methods = array_diff($methods,$parent_methods);
}
return $methods;
}

// 返回一个继承方法的数组。
function get_inherited_methods($object){
$methods = get_class_methods(get_class($object));

if(get_parent_class($object)){
$parent_methods = get_class_methods(get_class($object));
$methods = array_intersect($methods,$parent_methods);
}
return $methods;
}

// 返回一个父类的数组。
function get_lineage($object){
if(get_parent_class($object)){
$parent = get_parent_class($object);
$parent_object = new $parent;

$lineage = get_lineage($parent_object);
$lineage[] = get_class($object);
}
else{
$lineage = array(get_class($object));
}
return $lineage;
}

// 返回一个子类的数组。
function get_child_classes($object){
$classes = get_declared_classes();

$children = array();
foreach($classes as $class){
if(substr($class,0,2) == '_ _'){
continue;
}
$child = new $class;
if(get_parent_class($child) == get_class($object)){
$children[] = $class;
}
}
return $children;
}

// 显示一个对象的信息。
function print_object_info($object){
$class = get_class($object);
echo '<h2>Class</h2>';
echo"<p>$class</p>";

echo '<h2>Inheritance</h2>';

echo '<h3>Parents</h3>';
$lineage = get_lineage($object);
arrat_pop($lineage);
echo count($lineage) ? ('<p>' . join(' &gt; ',$lineage) . '</p>'):'<i>None</i>';
echo '<h3>Children</h3>';
$children = get_child_classes($object);
echo '<p>' . (count($children) ? join(',',$children) : '<i>None</i>') . </p>
echo '<h2>Methods</h2>';
$methods = get_class_methods($class);
$object_methods = get_methods($objects);
if(!count($methods)){
echo "<i>None</i><br/>";
}
else{
echo '<p>Inherited methods are in <i>italics</i>.</p>';
foreach($methods as $method){
echo in_array($method,$object_methods) ? "<b>$method</b>();<br/>" : "<i>$method</i>();<br/>";
}
}
echo '<h2>Properties<h2/>';
%properties = get_class_vars($class);
if(!count($properties)){
echo "<i>None</i><br/>";
}
else{
foreach(array_keys($properties) as $property){
echo "<b>\$$preperty</b> = " . $object->$property . '<br/>';
}
}
echo '<hr/>';
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!