浅谈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代码
Dec 06 PHP
php通用防注入程序 推荐
Feb 26 PHP
php 文件上传类代码
Aug 06 PHP
JpGraph php柱状图使用介绍
Aug 23 PHP
采用header定义为文件然后readfile下载(隐藏下载地址)
Jan 31 PHP
PHP实现简单汉字验证码
Jul 28 PHP
浅析Laravel5中队列的配置及使用
Aug 04 PHP
php微信公众号开发(4)php实现自定义关键字回复
Dec 15 PHP
使用PHPMailer发送邮件实例
Feb 15 PHP
Mac系统下安装PHP Xdebug
Mar 30 PHP
Yii2处理密码加密及验证的方法
May 12 PHP
PHP创建对象的六种方式实例总结
Jun 27 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
基于mysql的论坛(2)
2006/10/09 PHP
php中的boolean(布尔)类型详解
2013/10/28 PHP
使用symfony命令创建项目的方法
2016/03/17 PHP
Laravel使用PHPQRCODE实现生成带有LOGO的二维码图片功能示例
2017/07/07 PHP
Laravel 5+ .env环境配置文件详解
2020/04/06 PHP
JSON 教程 json入门学习笔记
2020/09/22 Javascript
javaScript(JS)替换节点实现思路介绍
2013/04/17 Javascript
js改变鼠标的形状和样式的方法
2014/03/31 Javascript
JS图片自动轮换效果实现思路附截图
2014/04/30 Javascript
最全的Javascript编码规范(推荐)
2016/06/22 Javascript
jQuery多级联动下拉插件chained用法示例
2016/08/20 Javascript
AngularJs  E2E Testing 详解
2016/09/02 Javascript
jquery动态赋值id与动态取id方法示例
2017/08/21 jQuery
Nodejs Express 通过log4js写日志到Logstash(ELK)
2018/08/30 NodeJs
微信小程序录音实现功能并上传(使用node解析接收)
2020/02/26 Javascript
JavaScript鼠标悬停事件用法解析
2020/05/15 Javascript
JS实现公告上线滚动效果
2021/01/10 Javascript
Python操作Excel之xlsx文件
2017/03/24 Python
django 类视图的使用方法详解
2019/07/24 Python
解决Django 在ForeignKey中出现 non-nullable field错误的问题
2019/08/06 Python
python 中的paramiko模块简介及安装过程
2020/02/29 Python
S’well Bottle保温杯官网:绝缘不锈钢水瓶
2018/05/09 全球购物
EJB需直接实现它的业务接口或Home接口吗,请简述理由
2016/11/23 面试题
土木工程应届生自荐信
2013/09/24 职场文书
HR喜欢的自荐信格式
2013/10/08 职场文书
运动会广播稿200米
2014/01/27 职场文书
高二政治教学反思
2014/02/01 职场文书
教师党员一句话承诺
2014/03/28 职场文书
工作散漫检讨书
2014/09/16 职场文书
考试作弊检讨书
2015/01/27 职场文书
西安兵马俑导游词
2015/02/02 职场文书
关于应聘教师的自荐信
2016/01/28 职场文书
go语言中fallthrough的用法说明
2021/05/06 Golang
Python趣味挑战之用pygame实现简单的金币旋转效果
2021/05/31 Python
Python使用OpenCV和K-Means聚类对毕业照进行图像分割
2021/06/11 Python
Python初学者必备的文件读写指南
2021/06/23 Python