面向对象的高级语言都应该提供了反射机制,可以动态的获取类的信息,否则语言就缺少灵活性,很多需求无法完成,php的反射相当于iOS里面的运行时方法。iOS的运行系统提供了一系列的C语言方法动态的获取类的信息,处理消息转发,php也提供了类似的实现,相比iOS使用更简便,下面是几个案例。
- 获取函数的信息
<?php
/**
* Created by PhpStorm.
* User: wangguodong
* Date: 17/3/2
* Time: 下午10:44
*/
/**
* 这是testfun的注释
*/
function testfun($name = 'test'){
echo "this is a $name method";
return 'a';
}
testfun();
//通过一个函数名初始化一个函数反射对象,取获取函数的相关信息
$ref_fun = new ReflectionFunction('testfun');
//函数的所在的文件
echo '<br>函数的文件位置是:'.$ref_fun->getFileName();
//获取函数的开始行编号
echo '<br>函数的起始位置是:'.$ref_fun->getStartLine();
//获取函数末尾的编号
echo '<br>函数的结束位置是:'.$ref_fun->getEndLine();
//函数的注释
echo '<br>函数的注释是:'.$ref_fun->getDocComment();
//获取参数的个数
echo '<br>函数的参数个数是:'.$ref_fun->getNumberOfParameters();
//获取具体的参数信息
echo '<br>函数的参数是:';print_r($ref_fun->getParameters());
//函数的返回值 --这里提示这个方法不存在
echo '<br>函数的返回值是:'.$ref_fun->getReturnType();
//如果反射一个不存在的函数,会抛出一个异常,应该try catch 使用
try{
$ref_nfun = new ReflectionFunction('no_exist');
}catch (ReflectionException $e){
echo $e->getMessage();
}
2.类的信息
class Person{
public $name,$age,$sex;
static function show($name,$age,$sex='男'){
echo "姓名:$name,年龄:$age,性别:$sex";
}
function say($content){
echo "我想说的是:$content";
}
function eat($food= 'apple'){
}
}
$per = new Person();
$ref = new ReflectionClass('Person');//参数可以是类名,或者类的实例
//获取类里面的所有方法
$class_methods = $ref->getMethods();
//是一个数组,每个对象包含了方法名和所属类
echo '<br/>';
echo "<pre>";print_r($class_methods);echo "<pre>";
//是否拥有某个方法
$has_method = $ref->hasMethod('say');
//获取某个方法的信息
$some_method = new ReflectionMethod('Person','say');
$some_method->isPrivate();//判断是否私有,还有static,public
//方法的调用,
if ($some_method->isPublic()&&!$some_method->isAbstract()) {
if ($some_method->isStatic()){
//静态方法第一个参数是null,后面参数写方法的参数,可以传递一个或者多个,并且这个方法可以接受数量可变的参数。
/*
* * The object to invoke the method on. For static methods, pass
* null to this parameter.
* </p>
* @param mixed $parameter [optional] <p>
* Zero or more parameters to be passed to the method.
* It accepts a variable number of parameters which are passed to the method.
* </p>
*/
$some_method->invoke(null,'zhangsan','23');
}
else {
//非静态方法第一个参数传递一个对象
$some_method->invoke($per,'生活真好');
}
}
}
- 动态代理
消息的转发,交给其他类处理,iOS可以通过delegate实现,也可以在运行时通过相应的方法转发。
//调用B的show方法时候去调用A的show方法
class A{
function show(){
echo "classA的show方法";
}
}
class B{
private $obj;
function __construct(){
$this->obj = new A();
}
function __call($name, $arguments)
{
$ref = new ReflectionClass($this->obj);
if ($ref->hasMethod($name)){
$method = $ref->getMethod($name);
if ($method->isPublic()&&!$method->isAbstract()&&count($arguments)){
if ($method->isStatic()){
$method->invoke(null);
}
else{
$method->invoke($this->obj);
}
}
}
}
}
- 插件案例
include_once __DIR__."/plugin.php";
function get_plugin_menus(){
$menus = array();
$all_class = get_declared_classes();//获取所有的类
foreach ($all_class as $cls){
$ref_cls = new ReflectionClass($cls);
if ($ref_cls->implementsInterface('Plugin')){//是否实现了某个接口
if ($ref_cls->hasMethod('showMenu')){
$method = $ref_cls->getMethod("showMenu");
if ($method->isStatic()){
$method->invoke(null);
}
else{
// $method->invoke(new $cls());//这样获取类
$instance = $ref_cls->newInstance();
$menu = $method->invoke($instance);
}
}
}
$menus = array_merge($menus,$menu);
}
return $menus;
}
echo "<pre>";get_plugin_menus();echo "<pre>";
interface Plugin{
function showMenu();
}
class MyPlugin implements Plugin{
function showMenu()
{
$menu = array(
array(
'name' => 'menu1', 'link' => 'index.php?act=link1'
),
array(
'name' => 'menu2', 'link' => 'index.php?act=link2'
)
);
return $menu;
}