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面试怎么实现反射注入的详细内容,更多请关注开心学习网其它相关文章!
- thinkphp伪静态实例(thinkPHP+mysql+ajax实现的仿百度一下即时搜索效果详解)
- thinkphp5 api开发(thinkphp5框架前后端分离项目实现分页功能的方法分析)
- php中row函数(PHP中number_format函数的用法讲解)
- php封装api(PHP常用的类封装小结4个工具类)
- phpstudy服务器怎么设置(phpstudy2018 访问目录服务权限问题)
- php八大模式详解(php设计模式之工厂模式用法经典实例分析)
- php联合注入列表总结(php中的依赖注入实例详解)
- phpsetcookie参数说明(PHP的cookie与session原理及用法详解)
- php可忽略大小写的模式符(PHP基于timestamp和nonce实现的防止重放攻击方案分析)
- php导出excel使用方法(PHP使用ajax的post方式下载excel文件简单示例)
- php运行机制与原理(PHP进阶学习之类的自动加载机制原理分析)
- thinkphp5访问路径(thinkphp5修改view到根目录实例方法)
- php开发技巧和方法(php+ajax实现商品对比功能示例)
- phpweb添加自定义模板(php静态化页面 htaccess写法详解htaccess怎么写?)
- thinkphp6.0安装(使用composer安装使用thinkphp6.0框架问题视频教程)
- php怎么设计状态模式(php设计模式之观察者模式定义与用法经典示例)
- 冯骥才 年意(冯骥才年意)
- ()
- 百事大吉蓝底 绿底手机高清壁纸(绿底手机高清壁纸)
- 蓝底证件照怎么制作 证件照换底色 换尺寸快速搞定(蓝底证件照怎么制作)
- 你喜欢足球吗 足球如何点亮世界的(足球如何点亮世界的)
- 不可分鸽是什么梗(不可分鸽是什么梗)
热门推荐
- js闭包可以解决哪些问题(JavaScript中let避免闭包造成问题)
- ILSpy反编译工具的使用
- python爬虫第一本书(我用Python抓取了7000 多本电子书案例详解)
- qgis 如何平滑折线(Sqlview动态发布地图图层的方法)
- _viewstart.cshtml的作用
- elasticsearch 索引创建过程(使用elasticsearch定时删除索引数据)
- word-wrap和break-word的区别
- 为什么mysql主键要设置自增列(浅谈MySQL中的自增主键用完了怎么办)
- 阿里云服务器慢怎么回事(阿里云服务器进入黑洞应该怎么办?)
- 微信小程序接入第三方支付的方法(小程序通过小程序云实现微信支付功能实例)
排行榜
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9