浅谈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 array_merge下进行数组合并的代码
Jul 22 PHP
PHP 配置open_basedir 让各虚拟站点独立运行
Nov 12 PHP
PHP 源代码压缩小工具
Dec 22 PHP
提高PHP编程效率的53个要点(经验小结)
Sep 04 PHP
PHP详解ASCII码对照表与字符转换
Dec 05 PHP
php 文件上传实例代码
Apr 19 PHP
header导出Excel应用示例
Jan 24 PHP
简单说说PHP优化那些事(经验分享)
Nov 27 PHP
使用php转义输出HTML到JavaScript
Mar 27 PHP
分享10段PHP常用代码
Nov 11 PHP
Symfony2框架学习笔记之HTTP Cache用法详解
Mar 18 PHP
php面试中关于面向对象的相关问题
Feb 13 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 at(@)符号的用法简介
2009/07/11 PHP
thinkphp区间查询、统计查询与SQL直接查询实例分析
2014/11/24 PHP
Cygwin中安装PHP方法步骤
2015/07/04 PHP
PHP函数checkdnsrr用法详解(Windows平台用法)
2016/03/21 PHP
php检查函数必传参数是否存在的实例详解
2017/08/28 PHP
学习ExtJS TextField常用方法
2009/10/07 Javascript
学习从实践开始之jQuery插件开发 对话框插件开发
2012/04/26 Javascript
容易造成JavaScript内存泄露几个方面
2014/09/04 Javascript
js带前后翻页的图片切换效果代码分享
2015/09/08 Javascript
当jquery ajax遇上401请求的解决方法
2016/05/19 Javascript
jQuery中deferred对象使用方法详解
2016/07/14 Javascript
jQuery查找节点方法完整实例
2016/09/13 Javascript
javascript工厂模式和构造函数模式创建对象方法解析
2016/12/30 Javascript
移动端刮刮乐的实现方式(js+HTML5)
2017/03/23 Javascript
jquery实现用户登陆界面(示例讲解)
2017/09/06 jQuery
解析vue中的$mount
2017/12/21 Javascript
浅谈vuex 闲置状态重置方案
2018/01/04 Javascript
bootstrap中日历范围选择插件daterangepicker的使用详解
2018/04/17 Javascript
微信小程序 调用远程接口 给全局数组赋值代码实例
2019/08/13 Javascript
Vue 实现分页与输入框关键字筛选功能
2020/01/02 Javascript
ant-design-vue 时间选择器赋值默认时间的操作
2020/10/27 Javascript
基于javascript实现移动端轮播图效果
2020/12/21 Javascript
Python WXPY实现微信监控报警功能的代码
2017/10/20 Python
Python实现的自定义多线程多进程类示例
2018/03/23 Python
Python 中的 global 标识对变量作用域的影响
2019/08/12 Python
tensorflow模型的save与restore,及checkpoint中读取变量方式
2020/05/26 Python
关于python3.7安装matplotlib始终无法成功的问题的解决
2020/07/28 Python
瑞典首都斯德哥尔摩的多元奢侈时尚品牌:Acne Studios
2017/07/09 全球购物
周仰杰(JIMMY CHOO)英国官方网站:闻名世界的鞋子品牌
2018/10/28 全球购物
六查六看自查材料
2014/02/17 职场文书
情人节寄语大全
2014/04/11 职场文书
学习实践科学发展观心得体会
2014/09/10 职场文书
学生无故旷课检讨书
2014/09/20 职场文书
房屋过户委托书范本
2014/10/07 职场文书
公务员年度个人总结
2015/02/12 职场文书
Python超简单容易上手的画图工具库推荐
2021/05/10 Python