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

这篇具有很好参考价值的文章主要介绍了浅谈PHP框架中类成员方法的类类型形参是怎么利用ReflectionClass反射类自动实例化的(应该是全网首发)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

说明

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

代码

<?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 {
                    //判断遍历出来的形参,在不在实际传递的实参数组中,如果在把这个值返回,如果不在,判断是否有默认值,如果有则返回,如果没有默认值,赋值为null
                    if (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名学生

到了这里,关于浅谈PHP框架中类成员方法的类类型形参是怎么利用ReflectionClass反射类自动实例化的(应该是全网首发)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python-面向对象:面向对象、成员方法 、类和对象、构造方法、魔术方法、封装、继承、类型注解、多态(抽象类(接口))

    当前版本号[20230806]。 版本 修改说明 20230806 初版 生活中数据的组织 学校开学,要求学生填写自己的基础信息,一人发一张白纸,让学生自己填, 易出现内容混乱 但当改为登记表,打印出来让学生自行填写, 就会整洁明了 程序中数据的组织 在程序中简单使用变量来记录学

    2024年02月14日
    浏览(38)
  • 《四》TypeScript 中类的类型定义

    类可以作为其实例对象的类型。 类也可以被当做是一个构造函数。 在 TypeScript 中,类的属性必须要明确声明,否则会报错。 在 TypeScript 中,类的属性和方法支持三种修饰符。添加之后,TypeScript 将会检测该成员在哪些地方可见。 public:修饰的是在任何地方可见、公有的属性

    2024年02月09日
    浏览(26)
  • Python框架【模板继承 、继承模板实战、类视图 、类视图的好处 、类视图使用场景、基于调度方法的类视图】(四)

    👏作者简介:大家好,我是爱敲代码的小王,CSDN博客博主,Python小白 📕系列专栏:python入门到实战、Python爬虫开发、Python办公自动化、Python数据分析、Python前后端开发 📧如果文章知识点有错误的地方,请指正!和大家一起学习,一起进步👀 🔥如果感觉博主的文章还不错的

    2024年02月11日
    浏览(42)
  • PHP8的类与对象的基本操作之类的实例化-PHP8知识详解

    定义完类和方法后,并不是真正创建一个对象。类和对象可以描述为如下关系。类用来描述具有相同数据结构和特征的“一组对象”,“类”是“对象”的抽象,而“对象”是“类”的具体实例,即一个类中的对象具有相同的“型”,但其中每个对象却具有各不相同的“值”

    2024年02月08日
    浏览(34)
  • Python中类属性和类方法

    使用面相对象开发,第 1 步 是设计 类 使用 类名() 创建对象,创建对象 的动作有两步: (1) 在内存中为对象 分配空间 (2) 调用初始化方法 __init__ 为 对象初始化 对象创建后,内存 中就有了一个对象的 实实在在 的存在 —— 实例 因此,通常也会把: 创建出来的 对象 叫做 类

    2023年04月21日
    浏览(32)
  • 不允许指针指向不完整的类类型

    问题原因 1:没有包含对应结构体的头文件 解决办法 1:直接添加相对应的头文件 问题原因 2:对应的结构体定义写在了C/CPP文件里 解决办法 2:将结构体定义写在对应的头文件中

    2024年02月07日
    浏览(30)
  • c++中,引用作为形参的使用方法和作用

    当在 C++ 函数中传递参数时,可以使用引用作为形参。引用是 C++ 中的一种特殊数据类型,它允许将变量的别名传递给函数,从而允许函数访问和操作原始变量。在函数参数中使用引用有以下几种用法和用途: 当一个函数需要修改传递进来的变量的值时,可以将变量作为引用

    2024年02月09日
    浏览(28)
  • 【Java基础篇】方法的使用(方法的使用以及形参实参的关系)

    作者简介: 辭七七,目前大一,正在学习C/C++,Java,Python等 作者主页: 七七的个人主页 文章收录专栏 :Java.SE,本专栏主要讲解运算符,程序逻辑控制,方法的使用,数组的使用,类和对象,继承和多态,抽象类和接口等内容 欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖💖 方

    2024年02月08日
    浏览(31)
  • 3种策略巧妙化解PHP Trait成员属性冲突

    PHP语言本身可以用insteadof和as解决多个trait同名成员方法冲突的问题,但是貌似没有直接解决同名成员属性冲突的方案。 虽然属性名冲突极少发生,但是不代表不会发生。 可以复制旧trait文件到新trait,改新文件的成员属性名,引用新trait。 直接更改原trait成员属性名,

    2024年02月19日
    浏览(29)
  • 【Java探索之旅】方法的概念 定义 执行流程 实参与形参的交互

    🎥 屿小夏 : 个人主页 🔥个人专栏 : Java编程秘籍 🌄 莫道桑榆晚,为霞尚满天! 方法是Java编程中非常重要的概念,它能够帮助我们组织代码、实现代码的重复使用,并使代码更加清晰易懂。本文将介绍方法的概念、定义以及调用执行过程,同时解释实参和形参之间的关

    2024年04月14日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包