当前位置: 首页 > news >正文

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.lryc.cn/news/369560.html

相关文章:

  • (2024,示例记忆,模型记忆,遗忘,差分评估,概率评估)深度学习中的记忆:综述
  • 硬件产品经理
  • AES加密、解密工具类
  • 普通人想要自学ai,该如何入手,看完这篇你就懂了,零基础教程!
  • Less的简单总结
  • Android:UI:Drawable:View/ImageView与Drawable
  • 网络安全实验BUAA-全套实验报告打包
  • 监控易监测对象及指标之:全面监控SQL Server 2008
  • 【学习记录】6.11 阅读记录
  • 100TOPS算力!16GB内存顶配NVIDIA Jetson Orin NX 16GB 开箱
  • OCP学习笔记-007 SQL语言之一:DQL
  • Git之解决重复输入用户名和密码(三十九)
  • Python 机器学习 基础 之 【实战案例】轮船人员获救预测实战
  • 安全相关的一些基础知识(持续更新)
  • 使用TensorFlow和Keras对以ResNet50模型进行微调
  • Shell脚本要点和难点以及具体应用和优缺点介绍
  • 移动端浏览器的扫描二维码实现(vue-qrcode-reader与jsQR方式)
  • android中调用onnxruntime框架
  • 【机器学习】与【数据挖掘】技术下【C++】驱动的【嵌入式】智能系统优化
  • Apollo9.0 PNC源码学习之Control模块(二)
  • 直线度测量仪发展历程!
  • 09-spring的bean创建流程(一)
  • spring中基于setting和构造器的注入方式
  • 爬虫基本原理?介绍|实现|问题解决
  • DevOps的原理及应用详解(六)
  • 手撸 串口交互命令行 及 AT应用层协议解析框架
  • Redis几种部署模式介绍
  • 【STM32HAL库学习】定时器功能、时钟以及各种模式理解
  • 3588麒麟系统硬解码实战
  • 十二 nginx中location重写和匹配规则