php各种绕过姿势(php面试实现反射注入的详细方法)
php各种绕过姿势
php面试实现反射注入的详细方法PHP具有完整的反射API,提供了对类、接口、函数、方法和扩展进行逆向工程的能力。通过类的反射提供的能力我们能够知道类是如何被定义的,它有什么属性、什么方法、方法都有哪些参数,类文件的路径是什么等很重要的信息。正是因为类的反射,很多PHP框架才能实现依赖注入自动解决类与类之间的依赖关系,这给我们平时的开发带来了很大的方便。
本文主要是讲解如何利用类的反射来实现依赖注入(Dependency Injection),并不会去逐条讲述PHP Reflection里的每一个API。为了更好地理解,我们通过一个例子来看类的反射,以及如何实现依赖注入。
下面这个类代表了坐标系里的一个点,有两个属性横坐标x和纵坐标y。
|
/** * Class Point */ class Point { public $x ; public $y ; /** * Point constructor. * @param int $x horizontal value of point's coordinate * @param int $y vertical value of point's coordinate */ public function __construct( $x = 0, $y = 0) { $this ->x = $x ; $this ->y = $y ; } } |
接下来这个类代表圆形,可以看到在它的构造函数里有一个参数是Point类的,即Circle类是依赖与Point类的。
|
class Circle { /** * @var int */ public $radius ; //半径 /** * @var Point */ public $center ; //圆心点 const PI = 3.14; public function __construct(Point $point , $radius = 1) { $this ->center = $point ; $this ->radius = $radius ; } //打印圆点的坐标 public function printCenter() { printf( 'center coordinate is (%d, %d)' , $this ->center->x, $this ->center->y); } //计算圆形的面积 public function area() { return 3.14 * pow( $this ->radius, 2); } } |
ReflectionClass
下面我们通过反射来对Circle这个类进行反向工程。把Circle类的名字传递给reflectionClass来实例化一个ReflectionClass类的对象。
|
$reflectionClass = new reflectionClass(Circle:: class ); //返回值如下 object(ReflectionClass)#1 (1) { [ "name" ]=> string(6) "Circle" } |
反射出类的常量
|
$reflectionClass ->getConstants(); |
返回一个由常量名称和值构成的关联数组
|
array (1) { [ "PI" ]=> float(3.14) } |
通过反射获取属性
|
$reflectionClass ->getProperties(); |
返回一个由ReflectionProperty对象构成的数组
|
array (3) { [0]=> object(ReflectionMethod)#2 (2) { [ "name" ]=> string(11) "__construct" [ "class" ]=> string(6) "Circle" } [1]=> object(ReflectionMethod)#3 (2) { [ "name" ]=> string(11) "printCenter" [ "class" ]=> string(6) "Circle" } [2]=> object(ReflectionMethod)#4 (2) { [ "name" ]=> string(4) "area" [ "class" ]=> string(6) "Circle" } } |
我们还可以通过getConstructor()来单独获取类的构造方法,其返回值为一个ReflectionMethod对象。
|
$constructor = $reflectionClass ->getConstructor(); |
反射出方法的参数
|
$parameters = $constructor ->getParameters(); |
其返回值为ReflectionParameter对象构成的数组。
|
array (2) { [0]=> object(ReflectionParameter)#3 (1) { [ "name" ]=> string(5) "point" } [1]=> object(ReflectionParameter)#4 (1) { [ "name" ]=> string(6) "radius" } } |
依赖注入
好了接下来我们编写一个名为make的函数,传递类名称给make函数返回类的对象,在make里它会帮我们注入类的依赖,即在本例中帮我们注入Point对象给Circle类的构造方法。
|
//构建类的对象 function make( $className ) { $reflectionClass = new ReflectionClass( $className ); $constructor = $reflectionClass ->getConstructor(); $parameters = $constructor ->getParameters(); $dependencies = getDependencies( $parameters ); return $reflectionClass ->newInstanceArgs( $dependencies ); } //依赖解析 function getDependencies( $parameters ) { $dependencies = []; foreach ( $parameters as $parameter ) { $dependency = $parameter ->getClass(); if ( is_null ( $dependency )) { if ( $parameter ->isDefaultValueAvailable()) { $dependencies [] = $parameter ->getDefaultValue(); } else { //不是可选参数的为了简单直接赋值为字符串0 //针对构造方法的必须参数这个情况 //laravel是通过service provider注册closure到IocContainer, //在closure里可以通过return new Class($param1, $param2)来返回类的实例 //然后在make时回调这个closure即可解析出对象 //具体细节我会在另一篇文章里面描述 $dependencies [] = '0' ; } } else { //递归解析出依赖类的对象 $dependencies [] = make( $parameter ->getClass()->name); } } return $dependencies ; } |
定义好make方法后我们通过它来帮我们实例化Circle类的对象:
|
$circle = make( 'Circle' ); $area = $circle ->area(); /*var_dump($circle, $area); object(Circle)#6 (2) { ["radius"]=> int(1) ["center"]=> object(Point)#11 (2) { ["x"]=> int(0) ["y"]=> int(0) } } float(3.14)*/ |
通过上面这个实例我简单描述了一下如何利用PHP类的反射来实现依赖注入,Laravel的依赖注入也是通过这个思路来实现的,只不过设计的更精密大量地利用了闭包回调来应对各种复杂的依赖注入。
以上就是php面试怎么实现反射注入的详细内容,更多请关注开心学习网其它相关文章!
- php批量导出所有数据库(php快速导入大量数据的实例方法)
- php网站经典案例(PHP生成短网址的思路以及实现方法的详解)
- php数组详解(php数组和链表的区别总结)
- thinkphp5怎么设置默认返回(thinkphp5.1框架实现格式化mysql时间戳为日期的方式小结)
- thinkphp5对接支付宝扫码支付(ThinkPHP框架下整合支付宝支付功能图文教程)
- php系统化框架教程(PHP+swoole+linux实现系统监控和性能优化操作示例)
- php简单定时执行任务(php实现 master-worker 守护多进程模式的实例代码)
- thinkphp使用说明(thinkphp框架使用JWTtoken的方法详解)
- php设置上传文件代码(PHP大文件切割上传并带进度条功能示例)
- 搭建php和mysql的运行环境(Windows环境开发PHP完整配置教程Apache+Mysql+PHP)
- php mq使用方法(PHP使用ActiveMQ实现消息队列的方法详解)
- php协议使用教程学习(php中的钩子理解及应用实例分析)
- php类的属性和方法(PHP进阶学习之反射基本概念与用法分析)
- php中最常用的标记符(php中目录操作opendir、readdir及scandir用法示例)
- php nginx 底层执行流程(nginx/apache/php隐藏http头部版本信息的实现方法)
- php 上传临时文件扩展名(浅析PHP 中move_uploaded_file 上传中文文件名失败)
- 今天是什么日子(今天是什么日子有什么特殊意义吗)
- 这里输入关键词(怎么输入关键词搜索)
- 34岁的舒畅,就这样走到了末路,不知会不会后悔15年前的草率决定(就这样走到了末路)
- 不走心的古装造型 舒畅 毁容式 出演,萧蔷雷出新高度(不走心的古装造型)
- 嘉南传 第22集(嘉南传第22集)
- 哪版孙悟空最萌 黄渤躺萌了(哪版孙悟空最萌)
热门推荐
- linq中join用法
- mysql的binlog日志详解(MySQL 有关MHA搭建与切换的几个错误log汇总)
- 选择哪个平台注册虚拟主机好(怎么选择好的便宜云虚拟主机?分享挑选便宜云虚拟主机的小技巧)
- html5标签怎么做(html5用video标签流式加载的实现)
- react初学难点(使用react的7个避坑案例小结)
- 宝塔面板进不去(宝塔面板打不开重启也不行的处理方法)
- dedecms中的有些功能如何修改(织梦DedeCMS默认文件夹重命名的方法)
- php性能优化的思路和步骤(FastCGI轻松搞定IIS7.5+PHP5.6.0环境)
- 对mysql性能优化的看法(聊聊MySQL的COUNT的性能,看看怎么最快?)
- nginx跨域怎么用(如何利用map实现Nginx允许多个域名跨域)
排行榜
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9