PHP反射机制详解

news/2024/5/19 2:26:55 标签: php, 反射

原文地址

什么是反射

反射机制就是不需要实例化对象,利用类名就可以获取关于这个类的一系列信息,具有对类、接口、函数、方法和扩展进行反向工程的能力。 直观理解就是根据结果找出原因。

此外,反射 API 提供了方法来取出函数、类和方法中的文档注释。

如何使用反射API

以下面代码为例

php">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';

现在,要获取这个student对象的方法和属性列表该怎么做?可以用反射来实现,代码如下

php">$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函数,返回对象属性的关联数组以及更多的信息:(针对于公开的属性和):

php">//返回对象属性的关联数组
var_dump(get_object_vars($boy));
//类属性
var_dump(get_class_vars(get_class($boy)));
//返回由类的属性的方法名组成的数组
var_dump(get_class_methods(get_class($boy)));

反射API的功能显然更强大,甚至能还原这个类的原型,包括方法的访问权限,以下简单封装了一个打印类的代码

php">/**
 * @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更是有几十个,可以说,反射完整地描述了一个类或者对象的原型.反射不仅可以用于类和对象,还可以用于函数,扩展模块,异常等.

反射可以做什么

反射一般在框架中使用到反射机制比较多(控制反转),自动加载插件,自动生成文档,甚至可以用来扩展PHP语言。但是正常情况下一般使用不到反射的。

既然反射可以探知类内部结构, 那么是不是 可以用它做hook实现插件功能呢?或者是作动态代理呢?抛砖引玉,以下代码是个简单的例子

php"><?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');

这里真正操作类是mysql类,但是sqlproxy实现了根据动态传入参数,代替实际的类运行,并且在方法运行前后进行拦截,并且动态地改变类中的方法和属性.这就是简单的动态代理.

在平常的开发中用到反射的地方并不多: 一个是对对象进行调试,别一个是获取类的信息.在MVC和插件开发中,使用反射很常见,但是反射的消耗也很大,在可以找到替代方案的情况下,就不要滥用.

PHP有Token函数,可以通过这个机制实现一些反射功能.从简单灵活的角度讲,使用已经提供的反射API是可取的.

很多时候,善用反射能保持代码的优雅和简洁,但反射也会破坏类的封装性,因为反射可以使本不应该暴露的方法或属性被强制暴露了出来,这既是优点也是缺点。


http://www.niftyadmin.cn/n/1765553.html

相关文章

一、 软件测试概述

1. 软件的概念 软件就是程序与文档的集合。 文档指软件从无到有整个生命周期中产生的各类图文集合。具体可包括用户需求规格说明书、需求分析、系统概要设计、系统详细设计、数据库设计、用户操作手册等。 2. 软件生命周期 生命周期包括需求定义、可行性分析、软件概要设计、软…

PHP使用error_log记录日志的使用方法和配置

原文地址 php error_log记录日志的使用方法和配置 对于PHP开发者来 说&#xff0c;一旦某个项目投入使用&#xff0c;应该立即将 display_errors选项关闭&#xff0c;以免因为这些错误所透露的路径、数据库连接、数据表等信息而遭到黑客攻击。 但是&#xff0c;任何一个产品…

MFC的规则DLL与扩展DLL

一.MFC规则DLL MFC规则DLL可以在该dll内部使用MFC&#xff0c;但是与应用程序的接口不能是MFC的。能够被所有支持dll的编程语言所写的应用程序使用&#xff0c;当然也包括使用MFC创建的应用程序。在这种动态链接库中包含一个从CWinApp中继承而来的类&#xff0c;DllMain函数也被…

面向接口编程

原文地址 什么叫面向接口编程 在一个面向对象的系统中&#xff0c;系统的各种功能是由许多不同的对象协作完成的。 在这种情况下&#xff0c;各个对象内部是如何实现自己的,对系统设计人员来讲就不那么重要了&#xff1b;而各个对象之间的协作关系则成为系统设计的关键。小到…

vue中created、watch、methods的区别,一般如何使用,在什么场景下使用

在Vue中&#xff0c;created、watch和methods是Vue实例中常用的三个选项。它们的作用和使用场景如下&#xff1a; created&#xff1a; 作用&#xff1a;created是Vue实例生命周期钩子函数之一&#xff0c;在Vue实例创建完成后立即调用。在created钩子函数中&#xff0c;可以执…

无法启动INTERNET连接共享。一个已经用IP地址配置的LAN连接需要自动IP地址

提问者采纳很简单 只要把你要共享的连接 192.168.0.1 0改成1 然后就可以共享了 共享后再改回来 就能上了 但是会出现IP冲突的~ 转载于:https://www.cnblogs.com/cj2014/p/3809604.html

PHP SPL标准库(辅助数据结构)

原文链接 一.什么是SPL&#xff1f; SPL是用于解决典型问题(standard problems)的一组接口与类的集合。 SPL&#xff0c;PHP 标准库&#xff08;Standard PHP Library&#xff09; &#xff0c;从 PHP 5.0 起内置的组件和接口&#xff0c;且从 PHP5.3 已逐渐的成熟。SPL 在所…

如何写复杂的SQL

这里需要使用到case when语句&#xff0c;这个就是sql中的if else语句&#xff1a; select a.ins_id, b.product_id, b.product_name, c.cust_id, c.cust_name, c.…