浅谈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 保留字列表
Oct 04 PHP
php gzip压缩输出的实现方法
Apr 27 PHP
关于svn冲突的解决方法
Jun 21 PHP
PHP+MySQL插入操作实例
Jan 21 PHP
10条php编程小技巧
Jul 07 PHP
PHP开发Apache服务器配置
Jul 15 PHP
在WordPress中使用PHP脚本来判断访客来自什么国家
Dec 10 PHP
PHP常见数组函数用法小结
Mar 21 PHP
PHP的Yii框架中过滤器相关的使用总结
Mar 29 PHP
PHP实现将标点符号正则替换为空格的方法
Aug 09 PHP
自写的利用PDO对mysql数据库增删改查操作类
Feb 19 PHP
PHP Swoole异步读取、写入文件操作示例
Oct 24 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 编程安全性小结
2010/01/08 PHP
PHP中的reflection反射机制测试例子
2014/08/05 PHP
php+mysqli实现批量执行插入、更新及删除数据的方法
2015/01/29 PHP
浅谈PHP中的
2016/04/23 PHP
PHP结合jquery ajax实现上传多张图片,并限制图片大小操作示例
2019/03/01 PHP
Jquery升级新版本后选择器的语法问题
2010/06/02 Javascript
JS刷新框架外页面七种实现代码
2013/02/18 Javascript
node.js中使用node-schedule实现定时任务实例
2014/06/03 Javascript
jQuery+ajax实现鼠标单击修改内容的思路
2014/06/29 Javascript
JsRender实用入门教程
2014/10/31 Javascript
Jquery实现瀑布流布局(备有详细注释)
2015/07/31 Javascript
jquery实现点击向下展开菜单项(伸缩导航)效果
2015/08/22 Javascript
jQuery.deferred对象使用详解
2016/03/18 Javascript
JavaScript闭包和范围实例详解
2016/12/19 Javascript
使用jquery datatable和bootsrap创建表格实例代码
2017/03/17 Javascript
Node.js使用orm2进行update操作时关联字段无法修改的解决方法
2017/06/13 Javascript
AngularJS2 与 D3.js集成实现自定义可视化的方法
2017/12/01 Javascript
vue.js select下拉框绑定和取值方法
2018/03/03 Javascript
详解Vue源码学习之callHook钩子函数
2018/07/25 Javascript
VUE注册全局组件和局部组件过程解析
2019/10/10 Javascript
vue项目中使用bpmn为节点添加颜色的方法
2020/04/30 Javascript
Angular进行简单单元测试的实现方法实例
2020/08/16 Javascript
python调用百度REST API实现语音识别
2018/08/30 Python
Python基于Tkinter模块实现的弹球小游戏
2018/12/27 Python
python数据类型之间怎么转换技巧分享
2019/08/20 Python
Tensorflow限制CPU个数实例
2020/02/06 Python
Python+Django+MySQL实现基于Web版的增删改查的示例代码
2020/05/13 Python
scrapy结合selenium解析动态页面的实现
2020/09/28 Python
Lombok插件安装(IDEA)及配置jar包使用详解
2020/11/04 Python
分享CSS3制作卡片式图片的方法
2016/07/08 HTML / CSS
你不知道的5个HTML5新功能
2016/06/28 HTML / CSS
飞利浦西班牙官方网站:Philips西班牙
2020/02/17 全球购物
会员卡清退活动总结
2014/08/27 职场文书
学雷锋团日活动总结
2015/05/06 职场文书
全民创业工作总结
2015/08/13 职场文书
七年级写作指导之游记作文
2019/10/07 职场文书