PHP实战开发24-一定要知道PHP中反射的强大应用

news2024/10/7 20:26:09

文章目录

  • 一、前言
    • 1.1 关于反射
    • 1.2 PHP中的反射
  • 二、反射的应用
    • 2.1 自动注入
    • 2.2 动态调用方法
    • 2.3 注解解析
  • 总结


一、前言

本文已收录于PHP全栈系列专栏:PHP快速入门与实战

1.1 关于反射

反射是一种编程语言的特性,它允许程序在运行时获取和操作对象的信息,包括类、方法、属性等。通过反射,程序可以动态地创建、修改和调用对象,从而实现更加灵活和智能化的功能。

1.2 PHP中的反射

PHP中的反射提供了一些常用的类和方法,比如ReflectionClass、ReflectionMethod、ReflectionFunction等,它们分别代表了类、方法、函数等的反射信息。开发者可以使用这些类及其方法来获取类的属性、方法、注释等信息,也可以通过反射实例化类、调用类的方法等。
在这里插入图片描述

通过PHP中的反射,开发者可以更加灵活地操作代码,实现一些在编写时难以预料的需求,比如动态调用类的某个方法、修改类的某些属性等。同时,反射也为系统提供了更多的信息,方便开发者进行代码分析和优化。

通过反射,我们可以写出更优雅,更具有架构性,可读性的代码。建议大家一定要掌握反射的使用。例如Java或者PHP中,反射是实现面向切面编程的重要组成部分。

二、反射的应用

2.1 自动注入

自动注入是指在对象创建时自动将依赖注入到对象中。通过反射可以获取对象的构造函数参数类型和相关属性,从而进行自动注入。

例如,我们定义了一个Person类,它依赖于Car和Driver类:

class Car {
    public function run() {
        echo "car is running";
    }
}

class Driver {
    public function drive() {
        echo "driver is driving";
    }
}

class Person {
    private $car;
    private $driver;

    public function __construct(Car $car, Driver $driver) {
        $this->car = $car;
        $this->driver = $driver;
    }

    public function driveCar() {
        $this->driver->drive();
        $this->car->run();
    }
}

如果我们需要创建一个Person对象并调用它的driveCar()方法,我们可以手动注入依赖:

$car = new Car();
$driver = new Driver();
$person = new Person($car, $driver);
$person->driveCar();

但是如果我们有很多类都依赖于Car和Driver,手动注入会变得非常繁琐。这时我们可以使用反射来进行自动注入:

$class = new ReflectionClass('Person');
$constructor = $class->getConstructor();
$params = $constructor->getParameters();
$dependencies = [];

foreach($params as $param) {
    $dependency = $param->getClass();
    $dependencies[] = new $dependency->name;
}

$person = $class->newInstanceArgs($dependencies);
$person->driveCar();

这段代码通过反射获取Person类的构造函数参数类型,然后创建相应的实例并放入$dependencies数组中。最后使用newInstanceArgs()方法创建Person对象并传入依赖。

2.2 动态调用方法

有时我们需要在运行时根据不同的条件动态调用不同的方法。通过反射,我们可以在运行时获取类的方法,并进行动态调用。

例如,我们定义了一个Greeting类,它有不同的sayHello()方法:

class Greeting {
    public function sayHello() {
        echo "Hello";
    }

    public function sayHi() {
        echo "Hi";
    }

    public function sayHola() {
        echo "Hola";
    }
}

现在我们需要根据用户的选择动态调用不同的sayHello()方法,可以使用反射来实现:

$class = new ReflectionClass('Greeting');
$method = "say" . ucfirst($userInput);
if($class->hasMethod($method)) {
    $object = $class->newInstance();
    $method = $class->getMethod($method);
    $method->invoke($object);
}

这段代码根据用户的输入构建要调用的方法名,并通过反射判断该方法是否存在。如果存在,创建一个新的Greeting对象并获取对应的方法对象,然后使用invoke()方法进行调用。
在这里插入图片描述

2.3 注解解析

注解是一种轻量级的元数据形式,可以在PHP源代码中添加注解信息,并在运行时解析。通过注解,我们可以将额外的信息附加到类、属性、方法等结构上。注解解析是面向切面编程的一种思想。
在这里插入图片描述

通过反射,我们可以在运行时获取注解信息并进行相应的处理。

例如,我们定义了一个带有注解的Person类:

/**
 * @Table(name="person")
 */
class Person {
    /**
     * @Column(name="id")
     */
    public $id;

    /**
     * @Column(name="name")
     */
    public $name;
}

注解@Table表示该类对应的数据库表名为"person",注解@Column表示该属性对应的数据库字段名为"id"或"name"。

现在我们需要根据注解的信息生成SQL语句创建对应的数据库表,可以使用反射来解析注解:

$class = new ReflectionClass('Person');
$tableAnnotation = $class->getDocComment();
$columns = [];

foreach($class->getProperties() as $property) {
    $columnAnnotation = $property->getDocComment();
    preg_match('/@Column\(name="(.*?)"\)/', $columnAnnotation, $matches);
    $columnName = $matches[1];
    $columns[$property->getName()] = $columnName;
}

preg_match('/@Table\(name="(.*?)"\)/', $tableAnnotation, $matches);
$tableName = $matches[1];

$sql = "CREATE TABLE $tableName (";

foreach($columns as $propertyName => $columnName) {
    $sql .= "$columnName INT NOT NULL, ";
}

$sql = rtrim($sql, ", ");
$sql .= ")";
echo $sql;

这段代码通过反射获取Person类的注解信息和属性信息,然后解析注解得到对应的表名和列名,最后根据列名生成SQL语句。

总结

以上就是今天介绍的内容,PHP中反射的强大应用,如果你有什么疑问或者建议,欢迎在下方评论区留言。后续更多内容将收录在专栏PHP快速入门与实战中,感谢大家支持。喜欢记得三联哟。

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

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

相关文章

kotlin从入门到精通之内置类型

基本类型 声明变量 val(value的简写)用来声明一个不可变的变量,这种变量在初始赋值之后就再也不能重新赋值,对应Java中的final变量。 var(variable的简写)用来声明一个可变的变量,这种变量在初始…

CUDA线程的线程层次结构,以及单个线程threadIdx如何使用stride来进行跳步操作,同时对多个数据进行计算

线程层次的概念: 简单说,就是一个grid有多个block,一个block有多个thread. grid有多大,用gridDim表示它有多少个block,具体分为gridDim.x, gridDim.y,gridDim.z。 block有多大,用blockDim表示它有多少个t…

SpringBoot项目结合@Slf4j将日志记录到磁盘和数据库

文章目录 1、背景介绍2、存本地2.1、配置文件2.2、使用 3、存数据库3.1、配置文件改造3.2、过滤器编写3.3、表准备3.4、添加依赖3.5、测试 4、优化4.1、日志定期删除4.2、分库处理4.3、环境 5、总结 1、背景介绍 现在我一个SpringBoot项目想记录日志,大概可以分为下…

深度学习助力版面分析技术,图像“还原”有方

您好,我是码农飞哥(wei158556),感谢您阅读本文,欢迎一键三连哦。 💪🏻 1. Python基础专栏,基础知识一网打尽,9.9元买不了吃亏,买不了上当。 Python从入门到精…

【Python 随练】分数序列

题目: 有一分数序列:2/1,3/2,5/3,8/5,13/8,21/13… 求出这个数列的前 20 项之和。 简介: 在本篇博客中,我们将研究一个有趣的数学问题:求解一个特殊数列的…

MySQL出现Specified key was too long; max key length is 3072 bytes解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

算法篇——动态规划 01背包问题 (js版)

416. 分割等和子集 给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。 链接:力扣 解题思路: 这道题看似是比较简单的背包问题: 首先可以通过判断数组和是否是…

MVC框架的model,view,controllr如何运作

第一步: MVC 是:model,view,controller 的缩写。 第二步: view负责界面显示,也就是jsp,html页面 controller是控制业务流程,也就是servlet,service等java文件 model是…

AI绘图网站 AI绘图生成器推荐

一、怎样设置关键词才能制作出美观高端的图片? 要在使用AI绘画软件时生成高端的优质图片,关键词的设置是不可或缺的重要因素。以下是一些关键词设置的建议。 确立你想要呈现的主题或题材 在设定关键字之前,你必须确定你所要表现的主题或题材…

基于pix实现无人机编队表演

文章目录 前言一、飞控LED灯光控制二、飞控路径控制三、飞控和地面站通信接口四、舞步设计五、gazebo仿真 前言 编队灯光表演没有什么高深的技术,主要是一些应用层的开发,事实上即使没有任何编程基础,按本教程操作也可以实现。 硬件准备&am…

spring security oauth2整合SSO(单点登录)

1.流程 用户在访问应用程序时,将被重定向到身份认证服务器进行身份验证。用户输入他们的凭据(通常是用户名和密码),身份认证服务器对其进行验证。身份认证服务器向用户颁发一个令牌,该令牌表示用户已经通过身份验证。…

正则表达式(1)

文章目录 正则表达式一.基础命令1.grep命令1.1grep格式1.2grep命令选项 2.特殊的符号2.1空行——^$2.2以什么为开头—^,以什么为结尾—$2.2.1以什么为开头的格式:2.2.2以什么为结尾的格式: 3.只匹配单行——^匹配的字符$ 二.文本处理命令1.sort命令1.1命…

使用大型语言模(LLM)构建系统(七):评估1

今天我学习了DeepLearning.AI的 Building Systems with LLM 的在线课程,我想和大家一起分享一下该门课程的一些主要内容。之前我们已经学习了下面这些知识: 使用大型语言模(LLM)构建系统(一):分类使用大型语言模(LLM)构建系统(二):内容审核、…

Java 10 新特性解读

前言  2018年3月21日,Oracle官方宣布Java10正式发布。  需要注意的是 Java 9 和 Java 10 都不是 LTS (Long-Term-Support) 版本。和过去的 Java 大版本升级不同,这两个只有半年左右的开发和维护期。而未 来的 Java 11,也就是 18.9 LTS&am…

SpringBoot基于Aop实现自定义日志注解(提供Gitee源码)

前言:日志在我们的日常开发当中是必定会用到的,在每个方法的上都会习惯性打上Log注解,这样系统就会自动帮我们记录日志,整体的代码结构就会非常优雅,这边我自己搭建了一个demo去实现了一些这个项目当中必定会用的功能。…

根据jar名称动态打包带版本的镜像, 并创建对应容器的脚本实现

根据jar名称动态打包带版本的镜像以及容器 利用shell脚本, 实现根据jar名称中的项目名和版本号来动态制作带版本的Docker镜像以及带版本的容器 背景 人人都逃不过的墨菲定律 事情的原因来自最近发生的一次生产环境事故: 我们在甲方那里环境中有两个服务器, 一个用于灰度测试另…

WPF开发txt阅读器16:自动编码检测

文章目录 更改编码重新载入自动编码检测更改编码并保存 txt阅读器系列: 需求分析和文件读写目录提取类💎列表控件与目录💎快捷键翻页字体控件绑定💎前景/背景颜色书籍管理系统💎用树形图管理书籍语音播放&#x1f48e…

Cortext-M3系统:储存器系统(2)

1、存储系统功能概览 Cortext-M3储存器有如下特点: 存储器映射是预定义的,并且还规定好了哪个位置使用哪条总线。 存储器系统支持所谓的“位带”(bit-band)操作。通过它,实现了对单一比特的原子操作,位带操…

STM32G0+EMW3080+阿里云实现单片机WiFi智能联网功能(一)EMW3080实现和PC之间的串口通讯

项目描述:该系列记录了STM32G0EMW3080实现单片机智能联网功能项目的从零开始一步步的实现过程; 硬件环境:单片机为STM32G030C8T6;物联网模块为EMW3080V2-P;网联网模块的开发板为MXKit开发套件,具体型号为XC…

基于tensorflow深度学习的猫狗分类识别

🤵‍♂️ 个人主页:艾派森的个人主页 ✍🏻作者简介:Python学习者 🐋 希望大家多多支持,我们一起进步!😄 如果文章对你有帮助的话, 欢迎评论 💬点赞&#x1f4…