浅谈PHP框架中类成员方法的类类型形参是怎么利用ReflectionClass反射类自动实例化的(应该是全网首发)

说明

1. 或许是全网首发,我翻过很多文章,从未有一个博主讲过这个东西,很多博主只讲了IOC、DI和反射机制的常见用法,因类类型形参反射的巧妙用法有相当高的难度和学习盲区,所以从未有人讲过类类型的形参它怎么就被自动实例化的。
2. 在Laravel框架,或者是其它框架中,类的成员方法中形参的类型定义为某个类,在方法体内就直接当做对象来调用,这并不是PHP本身自带的语法,而是利用了反射机制,一直很好奇是怎么实现的。然而框架源码又太繁重,所以采用原生的方式实现。
3. 反射的功能非常强大,反射可以针对类本身做很多开挂操作,因此PHP框架才会变得这么易用与强大,类类型形参实例化,仅仅是冰山一角,官方文档。

代码

<?php
/*** @Class 封装一个可自动实例化类的类类型的成员方法形参的容器*/
class AutoNew {/*** @function 递归实例化类构造方法中的数据* @param    $class string 类名* @return   object|null* @throws   ReflectionException*/public function newConstructClassTypeParam($class) {//实例化反射类$reflection = new ReflectionClass($class);//获取类的构造函数$constructor = $reflection->getConstructor();if ($constructor === null) {//如果构造函数存在,实例化这个类,(此方法支持给构造函数传参,如果有参数的话)return $reflection->newInstanceArgs();}//获取构造方法的参数,结果返回一个数组,若有值,返回的是ReflectionParameter类$params = $constructor->getParameters();$dependencies = [];foreach ($params as $param) {//获取构造方法参数的类型,注意:之有在变量左边声明类型的才可以,例如string $p获取的是string,但$p = 'ab'获取的就是null$dependencyType = $param->getType();//isBuiltin()方法,返回bool值,参数类型修饰符为string/int/bool/float/callable/array/object/mixed的都为true,但传输的内置外置接口,类都为false。目前使用PHP8,无法声明形参为null和resource类型if (($dependencyType !== null) && (! $dependencyType->isBuiltin())) {//获取形参声明的类型,返回字符串类型,字符串就是字符串,接口就是接口,类就是类$dependencyClassName = $dependencyType->getName();//此处可以理解为如果形参是类,或者是含有构造方法的抽象类或者接口的构造方法的形参中有以上类型,就递归实例化它$dependencies[] = $this->newConstructClassTypeParam($dependencyClassName);} else {//检测形参是否有默认值,如果有返回默认值,如果没有,返回null$dependencies[] = $param->isOptional() ? $param->getDefaultValue() : null;}}//如果构造函数存在,实例化这个类,(此方法支持给构造函数传参,如果有参数的话)return $reflection->newInstanceArgs($dependencies);}/*** @function 自动实例化某个类中某个方法的类类型的形参* @param    $class      string 类名* @param    $method     string 方法名* @param    $parameters array  参数名* @return   void* @throws   ReflectionException*/public function init($class, $method, $parameters = []) {//实例化PHP内置的反射类$reflection = new ReflectionClass($class);//检查方法是否已定义if ($reflection->hasMethod($method)) {//创建一个实例$instance = $this->newConstructClassTypeParam($class);//返回一个ReflectionMethod对象,获取方法的形参,和其它元信息,并填充到ReflectionMethod对象中$methodReflection = $reflection->getMethod($method);//返回数组,获取干净的形参数据$methodParams = $methodReflection->getParameters();$methodDependencies = [];foreach ($methodParams as $param) {//获取方法参数的类型,注意:只有在变量左边声明类型的才可以,例如string $p获取的是string,但$p = 'ab'获取的就是null$paramType = $param->getType();//isBuiltin()方法,返回bool值,参数类型修饰符为string/int/bool/float/callable/array/object/mixed的都为true,但传输的内置外置接口,类都为false。目前使用PHP8,无法将形参声明null和resource类型if (($paramType !== null) && (! $paramType->isBuiltin())) {//获取形参声明的类型,返回字符串类型,字符串就是字符串,接口就是接口名,类就是类名$dependencyClassName = $paramType->getName();//返回数组,数组的值是创建出来的对象。此处的逻辑可以理解为类成员方法的形参是类的,就实例化它$methodDependencies[] = $this->newConstructClassTypeParam($dependencyClassName);} else {//判断遍历出来的形参,在不在实际传递的实参数组中,如果在把这个值返回,如果不在,判断是否有默认值,如果有则返回,如果没有默认值,赋值为nullif (array_key_exists($param->getName(), $parameters)) {$args = $parameters[$param->getName()];} elseif ($param->isOptional()) {$args = $param->getDefaultValue();} else {$args = null;}$methodDependencies[] = $args;}}//调用创建的实例并传参$methodReflection->invokeArgs($instance, $methodDependencies);}}
}//调用端-------------------------------------------------------------------------------------
//相当于框架业务逻辑层的代码
class StudentService {/*** @function 通过班级id查询一个班有多少人* @param    $class_id* @return   int*/public function getStudentNum($class_id) {//sql ...return 123;}
}//相当于框架的控制器
class StudentController {/*** @function 此方法根据逻辑可要可不要* @return   void*/public function __construct() {echo '构造方法被调用了' . PHP_EOL;}/*** @function 模拟获取学生人数的方法* @param    $usersService StudentService 学生服务类* @param    $class_id     int            班级id* @param    $unit         string         单位* @return   void*/public function getStudentNum(StudentService $usersService, $class_id, $unit = '人') {echo $class_id . '班有' . $usersService->getStudentNum($class_id) . $unit . PHP_EOL;}
}//初始化Language类并调用getStudentNum方法且传参,传参的过程相当与前端请求接口携带的参数。整体相当于框架的路由
(new AutoNew())->init(StudentController::class, 'getStudentNum', ['class_id' => '7', 'unit' => '名学生']);//结果如下:
构造方法被调用了
7班有123名学生

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/129770.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringCloudTencent(上)

SpringCloudTencent 1.PolarisMesh介绍2.北极星具备的功能3.北极星包含的组件4.功能特性1.服务管理1.服务注册2.服务发现3.健康检查 2.配置管理 5.代码实战1.环境准备2.服务注册与发现3.远程调用 1.PolarisMesh介绍 1.北极星是腾讯开源的服务治理平台&#xff0c;致力于解决分…

RESTful接口实现与测试

目录标题 是什么&#xff1f;设计风格HTTP协议四种传参方式常用注解RequestBody与ResponseBodyRequestMapping注解RestController与ControllerPathVariable 与RequestParam 接受复杂嵌套对象参数Http数据转换的原理自定义HttpMessageConverter统一规划接口响应的数据格式实战&a…

【使用Python编写游戏辅助工具】第一篇:概述

引言 欢迎阅读本系列文章&#xff0c;本系列将带领读者朋友们使用Python来实现一个简单而有趣的游戏辅助工具。 写这个系列的缘由源自笔者玩了一款游戏。正巧&#xff0c;笔者对Python编程算是有一定的熟悉&#xff0c;且Python语言具备实现各种有趣功能的能力&#xff0c;因…

MySQL复习总结(一):基础篇

文章目录 一、MySQL概述二、SQL语句2.1 SQL分类2.2 DDL语言2.2.1 数据库操作2.2.2 表操作:通用2.2.3 表操作:修改2.2.4 表操作:删除 2.3 DML语言2.3.1 添加数据2.3.2 修改数据2.3.3 删除数据 2.4 DQL语言2.5 DCL语言 三、函数四、约束五、多表查询5.1 多表关系 六、事务6.1 事务…

Compose-Multiplatform在Android和iOS上的实践

本文字数&#xff1a;4680字 预计阅读时间&#xff1a;30分钟 01 简介 之前我们探讨过KMM&#xff0c;即Kotlin Multiplatform Mobile&#xff0c;是Kotlin发布的移动端跨平台框架。当时的结论是KMM提倡将共有的逻辑部分抽出&#xff0c;由KMM封装成Android(Kotlin/JVM)的aar和…

【LeetCode:80. 删除有序数组中的重复项 II | 双指针】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

DbUtils + Druid 实现 JDBC 操作 --- 附BaseDao

文章目录 Apache-DBUtils实现CRUD操作1 Apache-DBUtils简介2 主要API的使用2.1 DbUtils2.2 QueryRunner类2.3 ResultSetHandler接口及实现类 3 JDBCUtil 工具类编写3.1 导包3.2 编写配置文件3.3 编写代码 4 BaseDao 编写 Apache-DBUtils实现CRUD操作 1 Apache-DBUtils简介 com…

pytorch+LSTM实现使用单参数预测,以及多参数预测(代码注释版)

开发前准备&#xff1a; 环境管理&#xff1a;Anaconda python: 3.8 显卡&#xff1a;NVIDIA3060 pytorch: 到官网选择conda版本&#xff0c;使用的是CUDA11.8 编译器&#xff1a; PyCharm 简述&#xff1a; 本次使用seaborn库中的flights数据集来做试验&#xff0c;我们通过…

代码训练营第59天:动态规划part17|leetcode647回文子串|leetcode516最长回文子序列

leetcode647&#xff1a;回文子串 文章讲解&#xff1a;leetcode647 leetcode516&#xff1a;最长回文子序列 文章讲解&#xff1a;leetcode516 DP总结&#xff1a;动态规划总结 目录 1&#xff0c;leeetcode647 回文子串。 2&#xff0c;leetcode516 最长回文子串&#xff1…

多模态论文阅读之BLIP

BLIP泛读 TitleMotivationContributionModel Title BLIP: Bootstrapping Language-Image Pre-training for Unified Vision-Language Understanding and Generation Motivation 模型角度&#xff1a;clip albef等要么采用encoder-base model 要么采用encoder-decoder model.…

LeetCode--550. 游戏玩法分析 IV

文章目录 1 题目描述2 测试用例3 解题思路3.1 解法 1: 1 题目描述 Table: Activity ----------------------- | Column Name | Type | ----------------------- | player_id | int | | device_id | int | | event_date | date | | games_…

【halcon】选择一个最大的面积

背景 我们可以用select_shape_xld (Edges, SelectedXLD, area, and, 49000, 100000) 对面积筛选&#xff0c;但有时这得到的是一个数值&#xff0c;而不是一个值。 而我们想得到这个数组中的最大值&#xff0c;该怎么做呢&#xff1f; 获取最大的面积的轮廓 *面积选择 selec…

【ElasticSearch系列-03】ElasticSearch的高级句法查询Query DSL

ElasticSearch系列整体栏目 内容链接地址【一】ElasticSearch下载和安装https://zhenghuisheng.blog.csdn.net/article/details/129260827【二】ElasticSearch概念和基本操作https://blog.csdn.net/zhenghuishengq/article/details/134121631【二】ElasticSearch的高级查询Quer…

RAM和ROM的区别(详解)

RAM和ROM的区别 RAM&#xff08;随机存取存储器&#xff09;和ROM&#xff08;只读存储器&#xff09;都是计算机中常见的存储器类型&#xff0c;它们在计算机系统中有不同的作用和特性。 RAM&#xff08;随机存取存储器&#xff09;&#xff1a; 作用&#xff1a; 用于临时存储…

网络架构学习之FCNVMB(基于U-Net架构)

目录 一、U-Net介绍 1.1 网络简单介绍 1.2 网络特点 二、FCNVMB介绍 2.1 文章简介 2.2 网络简单介绍 2.3 代码介绍 2.4 跳跃连接 2.5 训练过程 2.6 FCNVMB与InversionNet的比较 一、U-Net介绍 1.1 网络简单介绍 U-Net是基于全卷积网络下一个语义分割应用于生物医学的深…

面试算法54:所有大于或等于节点的值之和

题目 给定一棵二叉搜索树&#xff0c;请将它的每个节点的值替换成树中大于或等于该节点值的所有节点值之和。假设二叉搜索树中节点的值唯一。例如&#xff0c;输入如图8.10&#xff08;a&#xff09;所示的二叉搜索树&#xff0c;由于有两个节点的值大于或等于6&#xff08;即…

小红书app拉新推广一手官签渠道 附地推网推项目攻略

小红书app拉新高价版本在”聚量推客“上架啦&#xff01; 可以通过小红书申请后在”聚量推客“进行报备&#xff0c;审核通过后即可开始推广 简单易做&#xff0c;仅允许 地推 网推 校园 社群 私域量等推广方式推广&#xff0c;属于百搭项目

自动化测试和性能测试面试题精选

自动化测试相关 包含 Selenium、Appium 和接口测试。 1. 自动化代码中&#xff0c;用到了哪些设计模式&#xff1f; 单例模式工厂模式PO模式数据驱动模式 2. 什么是断言&#xff1f; 检查一个条件&#xff0c;如果它为真&#xff0c;就不做任何事&#xff0c;用例通过。如果…

uniapp写一个计算器用于记账(微信小程序,APP)

提要&#xff1a;自己用uniapp写了一个记账小程序&#xff08;目前是小程序&#xff09;&#xff0c;写到计算器部分&#xff0c;在网上找了别人写的计算器&#xff0c;大多数逻辑都是最简单的&#xff0c;都不能满足一个记账计算器的基本逻辑。与其在网上找来找去&#xff0c;…

K8S运维 解决openjdk:8-jdk-alpine镜像时区和字体问题

目录 一、问题 二、解决 三、完整代码 一、问题 由于项目的Dockerfile中使用openjdk:8-jdk-alpine作为基础镜像来部署服务&#xff0c;此镜像存在一定问题&#xff0c;例如时差8小时问题&#xff0c;或是由于字体问题导致导出excel文件&#xff0c;图片处理内容为空等。 二…