浅谈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 smarty模版引擎中的缓存应用
Dec 11 PHP
php和javascript之间变量的传递实现代码
Dec 19 PHP
PHP mkdir()无写权限的问题解决方法
Jun 19 PHP
thinkphp3.2中Lite文件替换框架入口文件或应用入口文件的方法
May 21 PHP
PHP中使用GD库绘制折线图 折线统计图的绘制方法
Nov 09 PHP
Yii2 rbac权限控制之菜单menu实例教程
Apr 28 PHP
Yii2创建表单(ActiveForm)方法详解
Jul 23 PHP
Yii2实现自定义独立验证器的方法
May 05 PHP
PHP字典树(Trie树)定义与实现方法示例
Oct 09 PHP
Codeigniter里的无刷新上传的实现代码
Apr 14 PHP
php生成HTML文件的类方法
Oct 11 PHP
详解no input file specified 三种解决方法
Nov 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
1982年日本摄影师镜头下的中国孩子 那无忧无虑的童年
2020/03/12 杂记
Laravel框架数据库CURD操作、连贯操作总结
2014/09/03 PHP
PHP中preg_match正则匹配中的/u、/i、/s含义
2015/04/17 PHP
PHP实现腾讯与百度坐标转换
2017/08/05 PHP
让插入到 innerHTML 中的 script 跑起来的实现代码
2006/07/01 Javascript
jQuery图片的展开和收缩实现代码
2013/04/16 Javascript
jquery动态添加元素事件失效问题解决方法
2014/05/23 Javascript
NodeJS学习笔记之Connect中间件模块(二)
2015/01/27 NodeJs
CSS或者JS实现鼠标悬停显示另一元素
2016/01/22 Javascript
js实现千分符和保留几位小数的简单实例
2016/08/01 Javascript
jQuery过滤选择器经典应用
2016/08/18 Javascript
JS实现json的序列化和反序列化功能示例
2017/06/13 Javascript
AngularJS实现的输入框字数限制提醒功能示例
2017/10/26 Javascript
关于在vue 中使用百度ueEditor编辑器的方法实例代码
2018/09/14 Javascript
如何在Vue.js中实现标签页组件详解
2019/01/02 Javascript
JavaScript判断对象和数组的两种方法
2019/05/31 Javascript
vue项目部署到nginx/tomcat服务器的实现
2019/08/26 Javascript
javascript跳转与返回和刷新页面的实例代码
2019/11/20 Javascript
RC4文件加密的python实现方法
2015/06/30 Python
详解python之配置日志的几种方式
2017/05/22 Python
pandas多级分组实现排序的方法
2018/04/20 Python
Django添加sitemap的方法示例
2018/08/06 Python
python爬取微信公众号文章
2018/08/31 Python
20行python代码的入门级小游戏的详解
2019/05/05 Python
详解Python3除法之真除法、截断除法和下取整对比
2019/05/23 Python
python sorted函数的小练习及解答
2019/09/18 Python
python爬虫基础知识点整理
2020/06/02 Python
英国领先的名牌服装折扣零售商:Brown Bag Clothing
2019/01/08 全球购物
巴西Bo.Bô官方在线商店:经营奢侈品时尚业务
2020/03/16 全球购物
电脑租赁公司创业计划书
2014/01/08 职场文书
监察建议书范文
2014/03/12 职场文书
教师学习八项规定六项禁令思想汇报
2014/09/27 职场文书
网站文案策划岗位职责
2015/04/14 职场文书
2015年生产部工作总结范文
2015/05/25 职场文书
Nginx虚拟主机的配置步骤过程全解
2022/03/31 Servers
基于Python实现西西成语接龙小助手
2022/08/05 Golang