浅谈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 相关文章推荐
PHP4.04简明安装
Oct 09 PHP
PHP遍历二维数组的代码
Apr 22 PHP
解析Extjs与php数据交互(增删查改)
Jun 25 PHP
php 模拟 asp.net webFrom 按钮提交事件的思路及代码
Dec 02 PHP
浅谈ThinkPHP的URL重写
Nov 25 PHP
php实现的树形结构数据存取类实例
Nov 29 PHP
详解php的socket通信
Aug 11 PHP
php创建无限级树型菜单
Nov 05 PHP
php 二维数组时间排序实现代码
Nov 19 PHP
LNMP部署laravel以及xhprof安装使用教程
Sep 14 PHP
PHP实现使用DOM将XML数据存入数组的方法示例
Sep 27 PHP
PHP curl批处理及多请求并发实现方法分析
Aug 15 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 特殊字符处理函数
2008/09/05 PHP
PHP 5.3.1 安装包 VC9 VC6不同版本的区别是什么
2010/07/04 PHP
php通过ksort()函数给关联数组按照键排序的方法
2015/03/18 PHP
Symfony2之session与cookie用法小结
2016/03/18 PHP
form表单传递数组数据、php脚本接收的实例
2017/02/09 PHP
PHP基于自增数据如何生成不重复的随机数示例
2017/05/19 PHP
PHP基于面向对象封装的分页类示例
2019/03/15 PHP
基于Jquery的开发个代阴影的对话框效果代码
2011/07/28 Javascript
css值转换成数值请抛弃parseInt
2011/10/24 Javascript
javascript改变position值实现菜单滚动至顶部后固定
2013/01/18 Javascript
网站404页面3秒后跳到首页的实例代码
2013/08/16 Javascript
基于Jquery代码实现手风琴菜单
2015/11/19 Javascript
整理JavaScript对DOM中各种类型的元素的常用操作
2016/05/05 Javascript
Angular和百度地图的结合实例代码
2016/10/19 Javascript
深入理解vue.js中的v-if和v-show
2017/06/22 Javascript
Vue.js学习记录之在元素与template中使用v-if指令实例
2017/06/27 Javascript
Vue.js中extend选项和delimiters选项的比较
2017/07/17 Javascript
利用Node.js了解与测量HTTP所花费的时间详解
2017/09/22 Javascript
原生javascript实现文件异步上传的实例讲解
2017/10/26 Javascript
vuex actions传递多参数的处理方法
2018/09/18 Javascript
原生js拖拽功能制作滑动条实例代码
2021/02/05 Javascript
使用Python的turtle模块画国旗
2019/09/24 Python
Django Xadmin多对多字段过滤实例
2020/04/07 Python
python 错误处理 assert详解
2020/04/20 Python
CSS3教程:新增加的结构伪类
2009/04/02 HTML / CSS
Bandier官网:奢侈、时尚前卫的健身服装首选目的地
2020/07/05 全球购物
康拓普公司Java笔面试
2016/09/23 面试题
Java TransactionAPI (JTA) 主要包含几部分
2012/12/07 面试题
《最可爱的人》教学反思
2014/02/14 职场文书
元旦获奖感言
2014/03/08 职场文书
80后职场人的职业生涯规划
2014/03/08 职场文书
计算机专业自荐信范文
2014/05/28 职场文书
2014年教师节活动总结
2014/08/29 职场文书
授权收款委托书范本
2014/10/10 职场文书
同事去世追悼词
2015/06/23 职场文书
导游词之山海关
2019/12/10 职场文书