浅谈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 数组实例说明
Aug 18 PHP
提高php运行速度的一些小技巧分享
Jul 03 PHP
Window 7/XP 安装Apache 2.4与PHP 5.4 的过程详解
Jun 02 PHP
CodeIgniter CLI模式简介
Jun 17 PHP
php数组操作之键名比较与差集、交集赋值的方法
Nov 10 PHP
PHP中使用imagick生成PSD文件缩略图教程
Jan 26 PHP
php利用反射实现插件机制的方法
Mar 14 PHP
php实现的用户查询类实例
Jun 18 PHP
Zend Framework实现多服务器共享SESSION数据的方法
Mar 22 PHP
php 三大特点:封装,继承,多态
Feb 19 PHP
PHP获取数组中单列值的方法
Jun 10 PHP
在laravel中使用Symfony的Crawler组件分析HTML
Jun 19 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错误提示failed to open stream: HTTP request failed!的完美解决方法
2011/06/06 PHP
114啦源码(114la)不能生成地方房产和地方报刊问题4级页面0字节的解决方法
2012/01/12 PHP
php中用date函数获取当前时间有误的解决办法
2013/08/02 PHP
PHP读取RSS(Feed)简单实例
2014/06/12 PHP
标准版Eclipse搭建PHP环境的详细步骤
2015/11/18 PHP
深入理解PHP中的count函数
2016/05/31 PHP
Yii使用DeleteAll连表删除出现报错问题的解决方法
2016/07/14 PHP
js 无提示关闭浏览器页面的代码
2010/03/09 Javascript
基于jquery的划词搜索实现(备忘)
2010/09/14 Javascript
密码强度检测效果实现原理与代码
2013/01/04 Javascript
JS对img进行操作(换图片/切图/轮换/停止)
2013/04/17 Javascript
JQuery的ready函数与JS的onload的区别详解
2013/11/21 Javascript
浅谈JavaScript function函数种类
2014/12/29 Javascript
为JS扩展Array.prototype.indexOf引发的问题及解决办法
2015/01/21 Javascript
JavaScript引用类型Date常见用法实例分析
2018/08/08 Javascript
使用Vue实现移动端左滑删除效果附源码
2019/05/16 Javascript
浅析vue中的provide / inject 有什么用处
2019/11/10 Javascript
JS实现网站楼层导航效果代码实例
2020/06/16 Javascript
vant-ui AddressEdit地址编辑和van-area的用法说明
2020/11/03 Javascript
用Python编写生成树状结构的文件目录的脚本的教程
2015/05/04 Python
python脚本监控docker容器
2016/04/27 Python
深入理解Django中内置的用户认证
2017/10/06 Python
运行django项目指定IP和端口的方法
2018/05/14 Python
解决安装pycharm后不能执行python脚本的问题
2019/01/19 Python
Python产生一个数值范围内的不重复的随机数的实现方法
2019/08/21 Python
python实点云分割k-means(sklearn)详解
2020/05/28 Python
div或img图片高度随宽度自适应的方法
2020/02/06 HTML / CSS
美国在线购买和出售礼品卡网站:EJ Gift Cards
2019/06/09 全球购物
求职简历自荐信范文
2013/10/21 职场文书
有创意的广告词
2014/03/18 职场文书
超市优秀员工事迹材料
2014/05/01 职场文书
获奖感言一句话
2015/07/31 职场文书
Nginx配置Https安全认证的实现
2021/05/26 Servers
SpringBoot项目中控制台日志的保存配置操作
2021/06/18 Java/Android
Win11开始菜单添加休眠选项
2022/04/19 数码科技
Nginx如何获取自定义请求header头和URL参数详解
2022/07/23 Servers