PHP反射原理与用法深入分析


Posted in PHP onSeptember 28, 2019

本文实例讲述了PHP反射原理与用法。分享给大家供大家参考,具体如下:

说到反射,实际上包含两个概念:

  • 检视 introspection 判断类、方法是否存在,父子类关系,调用关系等,检视的函数文档
  • 反射 Reflection 获取类里的方法、属性,注释等,反射类的文档

PHP官方文档写得很清晰了,下面我就说一下具体的应用。

1.参数检测

有时候需要在函数里需要判断传入的参数类型是否合法。
这时可以使用is_a、is_subclass_of来检测。或者结合反射,做更多检测。

2.动态调用

在依赖注入中,常见到这种用法,比如Laravel5.5中的Container.php

public function build($concrete)
  {
    // If the concrete type is actually a Closure, we will just execute it and
    // hand back the results of the functions, which allows functions to be
    // used as resolvers for more fine-tuned resolution of these objects.
    if ($concrete instanceof Closure) {
      return $concrete($this, $this->getLastParameterOverride());
    }
    $reflector = new ReflectionClass($concrete);
    // If the type is not instantiable, the developer is attempting to resolve
    // an abstract type such as an Interface of Abstract Class and there is
    // no binding registered for the abstractions so we need to bail out.
    if (! $reflector->isInstantiable()) {
      return $this->notInstantiable($concrete);
    }
    $this->buildStack[] = $concrete;
    $constructor = $reflector->getConstructor();
    // If there are no constructors, that means there are no dependencies then
    // we can just resolve the instances of the objects right away, without
    // resolving any other types or dependencies out of these containers.
    if (is_null($constructor)) {
      array_pop($this->buildStack);
      return new $concrete;
    }
    $dependencies = $constructor->getParameters();
    // Once we have all the constructor's parameters we can create each of the
    // dependency instances and then use the reflection instances to make a
    // new instance of this class, injecting the created dependencies in.
    $instances = $this->resolveDependencies(
      $dependencies
    );
    array_pop($this->buildStack);
    return $reflector->newInstanceArgs($instances);
  }

上述代码先判断是否是闭包,如果是,直接返回。不是则通过new ReflectionClass($concrete);

生成反射类的实例,然后获取这个类的构造函数和参数,进行初始化的过程。

注意

反射里一个比较重要的用法invoke

当已知这个类的时候,可以通过构造ReflectionMethod来直接调用,如:

class HelloWorld {

  public function sayHelloTo($name) {
    return 'Hello ' . $name;
  }

}

$reflectionMethod = new ReflectionMethod('HelloWorld', 'sayHelloTo');
echo $reflectionMethod->invoke(new HelloWorld(), 'Mike');

当不知道这个类时,知道类的对象,可以用ReflectionObject获取ReflectionMethod后调用,如:

class HelloWorld {

  public function sayHelloTo($name) {
    return 'Hello ' . $name;
  }

}

$hello = new HelloWorld();

$refObj = new ReflectionObject($hello);
$refMethod = $refObj->getMethod('sayHelloTo');
echo $refMethod->invoke($hello,'Mike');

调用流程一般就是获取反射类ReflectionClass/反射对象ReflectionObject的实例,然后获取ReflectionMethod后,invoke。

3.获取注释,生成文档

比如PHPDoc

4.注解,增强版的注释,符合一定的规则

比如某些框架的路由,便是通过注解实现的。

5.不要为了反射而反射

PHP是一门动态语言,其实可以直接通过字符串来调用类或函数,如下:

class HelloWorld {
  public function sayHelloTo($name) {
    return 'Hello ' . $name;
  }
}
$hello = 'HelloWorld';
$helloSay = 'sayHelloTo';
$helloIntance = new $hello;
echo $helloIntance->$helloSay('Mike');

那么为什么还需要反射呢?

  • 功能更强大
  • 更安全,防止直接调用没有暴露的内部方法
  • 可维护,直接写字符串是硬编码

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
Session的工作方式
Oct 09 PHP
在PHP3中实现SESSION的功能(三)
Oct 09 PHP
PHP5 面向对象(学习记录)
Dec 02 PHP
PHP正确配置mysql(apache环境)
Aug 28 PHP
深入array multisort排序原理的详解
Jun 18 PHP
PHP imagegrabscreen和imagegrabwindow(截取网站缩略图)的实例代码
Nov 07 PHP
Laravel 5 框架入门(三)
Apr 09 PHP
分享PHP-pcntl 实现多进程代码
Sep 30 PHP
php实现文件管理与基础功能操作
Mar 21 PHP
php微信开发之图片回复功能
Jun 14 PHP
PHP开发实现快递查询功能详解
Apr 08 PHP
laravel 字段格式化 modle 字段类型转换方法
Sep 30 PHP
Windows服务器中PHP如何安装redis扩展
Sep 27 #PHP
php-fpm超时时间设置request_terminate_timeout资源问题分析
Sep 27 #PHP
thinkPHP+LayUI 流加载实现功能
Sep 27 #PHP
PHP的cookie与session原理及用法详解
Sep 27 #PHP
PHP下载文件函数与用法示例
Sep 27 #PHP
PHP的JSON封装、转变及输出操作示例
Sep 27 #PHP
php面向对象重点知识分享
Sep 27 #PHP
You might like
浅谈PHP强制类型转换,慎用!
2013/06/06 PHP
php使用递归计算文件夹大小
2014/12/24 PHP
浅谈Laravel中的一个后期静态绑定
2017/08/11 PHP
thinkphp中U方法按路由规则生成url的方法
2018/03/12 PHP
Laravel框架使用Seeder实现自动填充数据功能
2018/06/13 PHP
php ajax数据传输和响应方法
2018/08/21 PHP
jquery EasyUI的formatter格式化函数代码
2011/01/12 Javascript
如何获取JQUERY AJAX返回的JSON结果集实现代码
2012/12/10 Javascript
JS关键字变色实现思路及代码
2013/02/21 Javascript
cookie.js 加载顺序问题怎么才有效
2013/07/31 Javascript
JS记录用户登录次数实现代码
2014/01/15 Javascript
node.js中的path.dirname方法使用说明
2014/12/09 Javascript
javascript实现禁止鼠标滚轮事件
2015/07/24 Javascript
jQuery实现为LI列表前3行设置样式的方法【2种方法】
2016/09/04 Javascript
浅谈JS如何实现真正的对象常量
2017/06/25 Javascript
JS实现网页抢购功能(触发,终止脚本)
2017/11/27 Javascript
JS实现验证码倒计时的注册页面
2018/01/02 Javascript
webpack4 从零学习常用配置(小结)
2019/05/28 Javascript
微信小程序webview 脚手架使用详解
2019/07/22 Javascript
vue 数据遍历筛选 过滤 排序的应用操作
2020/11/17 Javascript
使用Python的PIL模块来进行图片对比
2016/02/18 Python
Python中元组,列表,字典的区别
2017/05/21 Python
pandas ix &iloc &loc的区别
2019/01/10 Python
Python多分支if语句的使用
2020/09/03 Python
美团网旗下网上订餐平台:美团外卖
2020/03/05 全球购物
北京RT科技有限公司.net工程师面试题
2013/02/15 面试题
高二美术教学反思
2014/01/14 职场文书
商场总经理岗位职责
2014/02/03 职场文书
查摆剖析材料范文
2014/09/30 职场文书
挂靠协议书
2015/01/27 职场文书
客户经理岗位职责
2015/01/31 职场文书
员工表扬信怎么写
2015/05/05 职场文书
六一儿童节新闻稿
2015/07/17 职场文书
golang中切片copy复制和等号复制的区别介绍
2021/04/27 Golang
Python虚拟环境virtualenv是如何使用的
2021/06/20 Python
Vue+Flask实现图片传输功能
2022/04/01 Vue.js