浅谈thinkphp5 instance 的简单实现


Posted in PHP onJuly 30, 2017

最近学习 ThinkPHP5,第一次看到 TestClass::instance() 就能创建 TestClass 实例的方法。感到很好奇,翻阅 ThinkPHP 的源代码,大体理解了 它的 设计思想,非常的先进。

老规矩,直接上代码:

<?php
class TestClass {
 
 public static function instance() {
  return new self();
 }
 
 public $data = [];
 
 public function __set($name, $val) {
  return $this->data[$name] = $val;
 }
 
 public function __get($name) {
  return $this->data[$name];
 }
}
 
$app1 = TestClass::instance();
$app1->key = 'Application 1';
echo $app1->key . '<br />';
?>

为了方便调用,也模仿 ThinkPHP 写了一个助手函数

<?php
function app() {
 return TestClass::instance();
}
 
$app2 = app();
$app2->key = 'Application 2';
echo $app2->key . '<br />';
?>

这样就简单的实现了 instance。

不过这种方法还有一个小问题,试想以下,调用100次,就需要创建100个实例,想想都觉得可怕。

给 Test 类 增加一个 静态属性,将创建的实例保存到这里。下次如果需要调用,则直接调用这个实例。

<?php
class TestClass {
 
 public static $instance; //用于缓存实例
 
 public $data = [];
 
 public static function instance() {
  //如果不存在实例,则返回实例
  if (empty(self::$instance)) {
   self::$instance = new self();
  }
  return self::$instance;
 }
 
 public function __set($name, $val) {
  return $this->data[$name] = $val;
 }
 
 public function __get($name) {
  return $this->data[$name];
 }
 
}
 
function app($option = []) {
 return TestClass::instance($option);
}
 
header('content-type:text/plain');
 
$result = [];
$app1 = app();
$app1->key = "Application 1"; //修改 key 为 Application 1
$result['app1'] = [
 'app1' => $app1->key, //实例中 key 为 Application 1
];
 
// 创建 app2,因为 instance 已经存在实例,直接返回 缓存的实例
$app2 = app();
$result['app2'] = [
 'setp1' => [
  'app1' => $app1->key, // Application 1
  'app2' => $app2->key, //因为直接调用的实例的缓存,所以 key 也是 Application 1
 ],
];
 
// 无论 app1,app2 都对在内存中 对应的同一个实例,无论通过谁修改,都能改变值
$app1->key = "Application 2";
$result['app2']['setp2'] = [
 'app1' => $app1->key, // Application 2
 'app2' => $app2->key, // Application 2
];
print_r($result);
?>

通过上边的实验,可以看到 无论调用多少次,都会使用同一个实例。这样就解决了效率低的问题。

到现在基本就满足大多数情况了,唯一的小缺陷,就是 可能 实例的 初始参数不同,这样没法灵活调用(常见的比如同一个程序调用两个数据库)。在 上边的 例子中稍作改造,以传入的参数为key,将不通的 实例缓存到数组中 就可以解决。

<?php
class TestClass {
 
 public static $instance = []; //用于缓存实例数组
 public $data = [];
 
 public function __construct($opt = []) {
  $this->data = $opt;
 }
 
 public static function instance($option = []) {
  // 根据传入的参数 通过 serialize 转换为字符串,md5 后 作为数组的 key
  $instance_id = md5(serialize($option));
  //如果 不存在实例,则创建
  if (empty(self::$instance[$instance_id])) {
   self::$instance[$instance_id] = new self($option);
  }
  return self::$instance[$instance_id];
 }
 
 public function __set($name, $val) {
  return $this->data[$name] = $val;
 }
 
 public function __get($name) {
  return $this->data[$name];
 }
 
}
 
function app($option = []) {
 return TestClass::instance($option);
}
 
header('content-type:text/plain');
 
$result = [];
//传入 初始数据
$app1 = app(['key' => '123']);
$result['init'] = $app1->key; // 使用 传入的数据,即:123
$app1->key = "app1";
$result['app'] = $app1->key; // 现在值改为了 自定义的 app1了
print_r($result);
 
$result = [];
// 创建 app2,注意 初始参数不一样
$app2 = app();
// 因为初始参数不一样,所以还是创建新的实例
$app2->key = "app2";
$result['app1'] = $app1->key; // app1
$result['app2'] = $app2->key; // app2
print_r($result);
 
$result = [];
// 创建 app3,传入的参数 和 app1 一样,所以会直接返回 和app1相同 的 实例
$app3 = app(['key' => '123']);
$result['log'] = [
 'app1' => $app1->key, // app1
 'app2' => $app2->key, // app2
 'app3' => $app3->key, // app1
];
 
// 设置 app3 的key,会自动修改 app1 的值,因为他们两个是同一个实例
$app3->key = 'app3';
$result['app3_set'] = [
 'app1' => $app1->key, // app3
 'app2' => $app2->key, // app2
 'app3' => $app3->key, // app3
];
 
// 同理,设置 app1 的key,app3 的 key 也会修改
$app1->key = 'app1';
$result['app1_set'] = [
 'app1' => $app1->key, // app1
 'app2' => $app2->key, // app2
 'app3' => $app3->key, // app1
];
print_r($result);
?>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
php读取msn上的用户信息类
Dec 05 PHP
Codeigniter注册登录代码示例
Jun 12 PHP
美图秀秀web开放平台--PHP流式上传和表单上传示例分享
Jun 22 PHP
kohana框架上传文件验证规则写法示例
Jul 14 PHP
ThinkPHP写数组插入与获取最新插入数据ID实例
Nov 03 PHP
ThinkPHP中关联查询实例
Dec 02 PHP
linux中cd命令使用详解
Jan 08 PHP
php实现将数组转换为XML的方法
Mar 09 PHP
PHP简单判断手机设备的方法
Aug 23 PHP
thinkphp 验证码 的使用小结
May 07 PHP
CI框架(CodeIgniter)公共模型类定义与用法示例
Aug 10 PHP
Yii2.0建立公共方法简单示例
Jan 29 PHP
PHP用PDO如何封装简单易用的DB类详解
Jul 30 #PHP
详解PHP防止直接访问.php 文件的实现方法
Jul 28 #PHP
php简单实现单态设计模式的方法分析
Jul 28 #PHP
[原创]PHP实现SQL语句格式化功能的方法
Jul 28 #PHP
使用php自动备份数据库表的实现方法
Jul 28 #PHP
PHP自定义函数判断是否为Get、Post及Ajax提交的方法
Jul 27 #PHP
PHP 7安装使用体验之性能大提升,兼容性强,扩展支持不够(升级PHP要谨慎)
Jul 27 #PHP
You might like
浅析PHP程序防止ddos,dns,集群服务器攻击的解决办法
2013/06/18 PHP
php使用Swoole实现毫秒级定时任务的方法
2020/09/04 PHP
jQuery 位置函数offset,innerWidth,innerHeight,outerWidth,outerHeight,scrollTop,scrollLeft
2010/03/23 Javascript
EasyUI中datagrid在ie下reload失败解决方案
2015/03/09 Javascript
jQuery实现自定义checkbox和radio样式
2015/07/13 Javascript
深入理解JavaScript中为什么string可以拥有方法
2016/05/24 Javascript
jQuery插件WebUploader实现文件上传
2016/11/07 Javascript
jQuery网页定位导航特效实现方法
2016/12/19 Javascript
zTree节点文字过多的处理方法
2017/11/24 Javascript
webpack 插件html-webpack-plugin的具体使用
2018/04/09 Javascript
ExtJs使用自定义插件动态保存表头配置(隐藏或显示)
2018/09/25 Javascript
gulp构建小程序的方法步骤
2019/05/31 Javascript
jQuery 选择方法及$(this)用法实例分析
2020/05/19 jQuery
html+vue.js 实现漂亮分页功能可兼容IE
2020/11/07 Javascript
原生js实现自定义滚动条组件
2021/01/20 Javascript
python 多线程实现检测服务器在线情况
2015/11/25 Python
Python使用MD5加密算法对字符串进行加密操作示例
2018/03/30 Python
利用Python如何制作好玩的GIF动图详解
2018/07/11 Python
Python中的 enum 模块源码详析
2019/01/09 Python
Python @property使用方法解析
2019/09/17 Python
tensorflow中tf.slice和tf.gather切片函数的使用
2020/01/19 Python
django admin管理工具自定义时间区间筛选器DateRangeFilter介绍
2020/05/19 Python
Python lambda表达式原理及用法解析
2020/08/18 Python
python3将变量输入的简单实例
2020/08/19 Python
HTML5之SVG 2D入门1—SVG(可缩放矢量图形)概述
2013/01/30 HTML / CSS
美国第二大团购网站:LivingSocial
2016/07/24 全球购物
亚洲独特体验旅游专家:eOasia
2018/08/15 全球购物
请写出 float x 与"零值"比较的 if 语句
2016/01/04 面试题
简单而又朴实的个人求职信分享
2013/12/12 职场文书
春节晚会主持词
2014/03/24 职场文书
先进事迹报告会主持词
2014/04/02 职场文书
2014年体育教师工作总结
2014/12/03 职场文书
2016大一新生军训感言
2015/12/08 职场文书
Pycharm 如何设置HTML文件自动补全代码或标签
2021/05/21 Python
8个JS的reduce使用实例和reduce操作方式
2021/10/05 Javascript
spring cloud eureka 服务启动失败的原因分析及解决方法
2022/03/17 Java/Android