php高级之框架源码、宏扩展原理与开发

在使用框架的时候我们经常会看到如下代码
在这里插入图片描述
类的方法不会显示地声明在代码里面,而是通过扩展的形式后续加进去,这么做的好处是可以降低代码的耦合度、保证源码的完整性、团队开发的时候可以分别写自己的服务去扩展类,减少代码冲突等等。我自己看着框架源码实现了这个功能。
以下是结果:
在这里插入图片描述
base代码
在这里插入图片描述
index.php

<?php
require_once "macroable.php";
require_once "base.php";
$a = new phpmacro\Base();
$a::macro("first",function (){$this->query .="I had be macro";return $this->query;
});
$a->first();
var_dump($a->query);

base.php

<?php
namespace phpmacro;/*** @method first()*/
class Base 
{use Macroable;public $query = "init-query";function __construct(){// code...echo "base-contruct";}
}

Macroable.php

<?phpnamespace phpmacro;use BadMethodCallException;
use Closure;
use ReflectionClass;
use ReflectionMethod;trait Macroable
{/*** The registered string macros.** @var array*/protected static $macros = [];/*** Register a custom macro.** @param  string  $name* @param  object|callable  $macro* @return void*/public static function macro($name, $macro){static::$macros[$name] = $macro;}/*** Mix another object into the class.** @param  object  $mixin* @param  bool  $replace* @return void** @throws \ReflectionException*/public static function mixin($mixin, $replace = true){$methods = (new ReflectionClass($mixin))->getMethods(ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED);foreach ($methods as $method) {if ($replace || ! static::hasMacro($method->name)) {static::macro($method->name, $method->invoke($mixin));}}}/*** Checks if macro is registered.** @param  string  $name* @return bool*/public static function hasMacro($name){return isset(static::$macros[$name]);}/*** Flush the existing macros.** @return void*/public static function flushMacros(){static::$macros = [];}/*** Dynamically handle calls to the class.** @param  string  $method* @param  array  $parameters* @return mixed** @throws \BadMethodCallException*/public static function __callStatic($method, $parameters){if (! static::hasMacro($method)) {throw new BadMethodCallException(sprintf('Method %s::%s does not exist.', static::class, $method));}$macro = static::$macros[$method];if ($macro instanceof Closure) {$macro = $macro->bindTo(null, static::class);}return $macro(...$parameters);}/*** Dynamically handle calls to the class.** @param  string  $method* @param  array  $parameters* @return mixed** @throws \BadMethodCallException*/public function __call($method, $parameters){if (! static::hasMacro($method)) {throw new BadMethodCallException(sprintf('Method %s::%s does not exist.', static::class, $method));}$macro = static::$macros[$method];if ($macro instanceof Closure) {$macro = $macro->bindTo($this, static::class);}return $macro(...$parameters);}
}

其实原理就是利用了静态调用的魔术方法与匿名函数的bindTo方法实现了类与方法解藕的效果
以下是test.php,可以清晰的看明白匿名函数bindTo跟bind是怎么用的

<?php
/** * 复制一个闭包,绑定指定的$this对象和类作用域。 * * @author 疯狂老司机 */
class Animal {private static $cat = "cat";private $dog = "dog";public $pig = "pig";
}/* * 获取Animal类静态私有成员属性*/
$cat = static function() {return Animal::$cat;
};/* * 获取Animal实例私有成员属性*/
$dog = function() {return $this->dog;
};/* * 获取Animal实例公有成员属性*/
$pig = function() {return $this->pig;
};$bindCat = Closure::bind($cat, null, new Animal());// 给闭包绑定了Animal实例的作用域,但未给闭包绑定$this对象
$bindDog = Closure::bind($dog, new Animal(), 'Animal');// 给闭包绑定了Animal类的作用域,同时将Animal实例对象作为$this对象绑定给闭包
$bindPig = Closure::bind($pig, new Animal());// 将Animal实例对象作为$this对象绑定给闭包,保留闭包原有作用域
$animal = new Animal();
$pigBindto = $pig->bindTo($animal);
echo $pigBindto()."\r\n";
echo $bindCat()."\r\n";// 根据绑定规则,允许闭包通过作用域限定操作符获取Animal类静态私有成员属性
echo $bindDog()."\r\n";// 根据绑定规则,允许闭包通过绑定的$this对象(Animal实例对象)获取Animal实例私有成员属性
echo $bindPig()."\r\n";// 根据绑定规则,允许闭包通过绑定的$this对象获取Animal实例公有成员属性

输出结果
在这里插入图片描述

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

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

相关文章

C语言之常用字符串函数总结、使用和模拟实现

文章目录 目录 一、strlen 的使用和模拟实现 二、strcpy 的使用及模拟实现 三、strcat 的使用和模拟实现 四、strcmp 的使用和模拟实现 五、strncpy 的使用和模拟实现 六、strncat 的使用和模拟实现 七、strncmp 的使用和模拟实现 八、strstr 的使用和模拟实现 九、st…

使用Python批量处理Excel的内容

正文共&#xff1a;1500 字 10 图&#xff0c;预估阅读时间&#xff1a;1 分钟 在前面的文章中&#xff08;如何使用Python提取Excel中固定单元格的内容&#xff09;&#xff0c;我们介绍了如何安装Python环境和PyCharm工具&#xff0c;还利用搭好的环境简单测试了一下ChatGPT提…

Java 数据类型 -- Java 语言的 8 种基本数据类型、字符串与数组

大家好&#xff0c;我是栗筝i&#xff0c;这篇文章是我的 “栗筝i 的 Java 技术栈” 专栏的第 004 篇文章&#xff0c;在 “栗筝i 的 Java 技术栈” 这个专栏中我会持续为大家更新 Java 技术相关全套技术栈内容。专栏的主要目标是已经有一定 Java 开发经验&#xff0c;并希望进…

如何秒杀系统架构设计

原文路径:https://learn.lianglianglee.com/%e4%b8%93%e6%a0%8f/%e5%a6%82%e4%bd%95%e8%ae%be%e8%ae%a1%e4%b8%80%e4%b8%aa%e7%a7%92%e6%9d%80%e7%b3%bb%e7%bb%9f/00%20%e5%bc%80%e7%af%87%e8%af%8d%20%e7%a7%92%e6%9d%80%e7%b3%bb%e7%bb%9f%e6%9e%b6%e6%9e%84%e8%ae%be%e8%ae%…

纳什均衡:博弈论中的运作方式、示例以及囚徒困境

文章目录 一、说明二、什么是纳什均衡&#xff1f;2.1 基本概念2.2 关键要点 三、理解纳什均衡四、纳什均衡与主导策略五、纳什均衡的例子六、囚徒困境七、如何原理和应用7.1 博弈论中的纳什均衡是什么&#xff1f;7.2 如何找到纳什均衡&#xff1f;7.3 为什么纳什均衡很重要&a…

素数的无穷大的证明

素数的无穷大——欧几里得的证明 文章目录 一、说明二、欧几里得证据三、哥德巴赫对素数无穷性的证明&#xff08;1730&#xff09;四、Frstenberg 对素数无穷性的证明(1955)五、库默尔对欧几里得证明的重述 一、说明 众所周知&#xff0c;素数是无限多的。然而&#xff0c;两…

运维一个宝塔面板的php项目的艰辛历程【解决了http3,ssl,quic】

在这个项目的环境 使用了宝塔面板 有4个php:php5.6,php7.3,php7.4,php8.0 nignx为1.20版本 升级计划&#xff1a; 升级nginx1.26.0版本&#xff0c;添加上http3协议&#xff0c;添加ssl证书 遇到的问题&#xff1a; 升级nginx1.26版本后 无法打开php5.6的后台 原因&#xff…

vmware-17虚拟机安装教程,安装linux centos系统

下载VMware 1.进入VMware官网&#xff1a;https://www.vmware.com/sg/products/workstation-pro.html 2.向下翻找到&#xff0c;如下界面并点击“现在安装” 因官网更新页面出现误差&#xff0c;现提供vmware17安装包网盘链接如下&#xff1a; 链接&#xff1a;https://pan.b…

Vue17-条件渲染

一、使用v-show属性做条件渲染 控制元素的显示和隐藏 v-show里面也能是表达式&#xff0c;只要表达式的值是boolean就行。 或者 当时结构还在&#xff1a; 二、使用v-if属性做条件渲染 结构也不在了 三、示例 方式一&#xff1a; 方式二&#xff1a; 当元素有很高的切换频率&am…

从0开始学人工智能测试节选:Spark -- 结构化数据领域中测试人员的万金油技术(四)

上一章节我们了解了 shuffle 相关的概念和原理后其实可以发现一个问题&#xff0c;那就是 shuffle 比较容易造成数据倾斜的情况。 例如上一节我们看到的图&#xff0c;在这批数据中&#xff0c;hello 这个单词的行占据了绝大部分&#xff0c;当我们执行 groupByKey 的时候触发了…

刚刚❗️德勤2025校招暑期实习测评笔试SHL测评题库已发(答案)

&#x1f4e3;德勤 2024暑期实习测评已发&#xff0c;正在申请的小伙伴看过来哦&#x1f440; ㊙️本次暑期实习优先考虑2025年本科及以上学历的毕业生&#xff0c;此次只有“审计及鉴定”“税务与商务咨询”两个部门开放了岗位~ ⚠️测评注意事项&#xff1a; &#x1f44…

使用Nextjs学习(学习+项目完整版本)

创建项目 运行如下命令 npx create-next-app next-create创建项目中出现的各种提示直接走默认的就行,一直回车就行了 创建完成后进入到项目运行localhost:3000访问页面,如果和我下面页面一样就是创建项目成功了 整理项目 将app/globals.css里面的样式都删除,只留下最上面三…

【LeetCode算法】第112题:路径总和

目录 一、题目描述 二、初次解答 三、官方解法 四、总结 一、题目描述 二、初次解答 1. 思路&#xff1a;二叉树先序遍历。首先访问根节点&#xff0c;若根节点是叶子节点并且值等于目标值&#xff0c;则返回true&#xff0c;否则递归访问左子树和右子树&#xff0c;只要左…

PG 数据库常用参数调整

1.shard_buffers Postgresql使用自己的缓冲区,也使用操作系统缓冲区。这意味着数据存储在内存中两次,首先是 Postgresql缓冲区,然后是操作系统缓冲区。 与其他数据库不同, Postgresql不提供直接IO。这称为双缓冲&#xff08;就是磁盘中的时候读的时候先放在数据库的缓冲区&am…

【上下界分析 差分数组】798得分最高的最小轮调

本文涉及知识点 差分数组 本题同解 C算法前缀和的应用&#xff1a;798得分最高的最小轮调 LeetCode798得分最高的最小轮调 给你一个数组 nums&#xff0c;我们可以将它按一个非负整数 k 进行轮调&#xff0c;这样可以使数组变为 [nums[k], nums[k 1], … nums[nums.lengt…

Web学习_SQL注入_布尔盲注

盲注就是在SQL注入过程中&#xff0c;SQL语句执行后&#xff0c;查询到的数据不能 回显到前端页面。此时&#xff0c;我们需要利用一些方法进行判断或者尝 试&#xff0c;这个过程称之为盲注。而布尔盲注就是SQL语句执行后&#xff0c;页面 不返回具体数据&#xff0c;数据库只…

未卸载干净的proteus安装教程7.8

提醒&#xff1a; 针对第一次安装推荐博文&#xff1a;https://jingyan.baidu.com/article/656db918f8590de381249cbf.html 1、一定要以管理员身份运行软件。 2、以管理员身份运行软件后&#xff0c;默认的ISIS Professional路径是C:\Program Files \Labcenter Electronics\…

802.11漫游流程简单解析与笔记_Part1

最近在进行和802.11漫游有关的工作&#xff0c;需要对wpa_supplicant认证流程和漫游过程有更多的了解&#xff0c;所以通过阅读论文等方式&#xff0c;记录整理漫游相关知识。Part1将记录802.11漫游的基本流程、802.11R的基本流程、与认证和漫游都有关的三层秘钥基础。Part1将包…

Excel行列条件转换问题,怎么实现如图一到图二的效果?

图一 图二 如果数据比较&#xff0c;不建议一上来就用公式&#xff0c;风速值那一列的数据可以确定都是数值型数字&#xff0c;可以先试试用数据透视表做转换工具&#xff1a; 1.创建数据透视表 将采集时间放在行字段&#xff0c;测风放在列字段&#xff0c;风速放在值字段 2.…