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);
|
- 函数
get_parent_class()
的参数可以是类名或对象名,返回值为父类名,如没有父类,则返回FALSE:
1 2 3 4 5
| class A{} class B extends A{} $obj = new B; echo get_parent_class($obj); echo get_parent_class(B);
|
自省程序示例
示例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(' > ',$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/>'; }
|