0

0

TP5之Cache的原理及使用

*文

*文

发布时间:2018-05-11 15:09:17

|

25687人浏览过

|

来源于php中文网

原创

在当今大流量的互联网之中,cache的重要性不言而喻。thinkphp5作为国内主流框架,提供了强大的cache功能。让我们跟随本文,来剖析tp5 cache的原理及使用。

为什么需要Cache(缓存)?

假设现在有一个小说网,有非常多的读者,有一篇新的章节更新了,那么可能一分钟内有几万几十万的访问量.

如果没有缓存,同样的内容就要去数据库重复查询,那可能网站一下就挂掉了.

追求性能的web站点应该充分利用缓存,常见的缓存类型有File,Memcache,Redis等,这里就不说他们的区别了

今天我们分析下TP5 Cache的内部实现原理.

首先看官方文档如何使用缓存的.

1.png

如上图,调用Cache类的的静态方法set就可以直接使用了,我们查看Cache类文件  在application/thinkphp/library/think目录下

   protected static $instance = [];    
   public static $readTimes   = 0;    
   public static $writeTimes  = 0;   
   /**
     * 操作句柄
     * @var object
     * @access protected     */
    protected static $handler;     /**
     * 写入缓存
     * @access public
     * @param string        $name 缓存标识
     * @param mixed         $value  存储数据
     * @param int|null      $expire  有效时间 0为永久
     * @return boolean     */
    public static function set($name, $value, $expire = null)
    {
        self::$writeTimes++;       
         return self::init()->set($name, $value, $expire);
    }

看到原来set方法是这样的, 其中writeTimes 是Cache类的静态变量,主要记录缓存的读取次数,这不是重点.

注意到了吗,有个静态变量命名为 $instance, 上次说过这样命名大概率就是 单例模式了.

set方法的重点是init方法

我们再看init方法

  public static function init(array $options = [])
    {        if (is_null(self::$handler)) {            // 自动初始化缓存
            if (!empty($options)) {                
            $connect = self::connect($options);
            } elseif ('complex' == Config::get('cache.type')) {                
            $connect = self::connect(Config::get('cache.default'));
            } else {                
            $connect = self::connect(Config::get('cache'));
            }
            self::$handler = $connect;
        }        return self::$handler;
    }

handler就是操作的句柄(巨饼:-) ), 这里一看,果然是单例模式了,如果句柄为空才去初始化对象,不然直接返回.句柄

同样,这里重点是connect函数, 传入的参数是 配置信息

同样,我们查看connect方法

/**
     * 连接缓存
     * @access public
     * @param array         $options  配置数组
     * @param bool|string   $name 缓存连接标识 true 强制重新连接
     * @return Driver
     */
    public static function connect(array $options = [], $name = false)
    {

        $type = !empty($options['type']) ? $options['type'] : 'File';
        if (false === $name) {
            $name = md5(serialize($options));
        }

        if (true === $name || !isset(self::$instance[$name])) {
            $class = false !== strpos($type, '\\') ? $type : '\\think\\cache\\driver\\' . ucwords($type);
            // 记录初始化信息
            App::$debug && Log::record('[ CACHE ] INIT ' . $type, 'info');
            if (true === $name) {
                return new $class($options);
            } else {
                self::$instance[$name] = new $class($options);
            }
        }

        return self::$instance[$name];
    }

 self::$instance[$name] = new $class($options); 这一句里,我们就可以知道句柄的真实身份拉,
 $class = false !== strpos($type, '\\') ? $type : '\\think\\cache\\driver\\' . ucwords($type);  
 这一句的意思是class的名字由type决定,  如果type没有包含反斜线, 则class = \think\cache\driver\.ucwords($type)
 thinkPhp 是把think作为核心目录的别名的,所以他真实路径就是 \thinkphp\libray\\think\driver\.ucwords($type)
 根据自动加载的尿性,自然是去该文件夹下加载对应的对象
 (额外提一句,这利用的是PHP动态变量的一个特性,其实就和工厂模式一个原理,运行中动态决定实例化的对象)
 type是什么呢? type就是函数传入的参数,也就是配置信息,我们看下配置信息
2.pngtype就是驱动方式,如果我们type填写的是File,那么就使用文件驱动,实例化的是 \think\cache\driver\File.class
我们看下 \think\cache\driver文件下有什么文件,那就知道thinkphp为我们提供了多少种缓存驱动了

3.png

原来有这么多!

点进去

每个文件,我们可以发现一个共同点, 每个类都是继承了 抽象类 Driver

Driver决定了 每一个Cache驱动应该是什么样子的,他们的方法基本是一样的,而实现方式因每个驱动不同而异

ERMEB域名PHP离线网络授权系统
ERMEB域名PHP离线网络授权系统

感谢您选择使用ERMEB域名授权离线网络验证系统(简称:ERMEB域名授权系统)是ERMEB团队开发,ERMEB域名授权系统是国内最稳定,最强大,最先进的域名授权管理平台解决方案之一,ERMEB域名授权系统采用PHP +Mysql的技术,ERMEB域名授权系统框架使用Thinkphp6/mysql数据库基于Markdown开发者文档开发而成,项目安装请参考ThinkPHP官方文档及下面的服务环境说

下载

其实这就是 适配器模式,如果是我们自己写,当然不会写那么多拉,不过TP5是为了造福广大PHP开发者,所以编写了那么多不同的驱动供我们使用.

我们重点看Redis吧,  如果要去实验,记得把 config中的 Cache.type更改为 redis

Redis类的方法很少,先看看构造函数

public function __construct($options = [])
    {
        if (!extension_loaded('redis')) {
            throw new \BadFunctionCallException('not support: redis');
        }
        if (!empty($options)) {
            $this->options = array_merge($this->options, $options);
        }
        $func          = $this->options['persistent'] ? 'pconnect' : 'connect';
        $this->handler = new \Redis;
        $this->handler->$func($this->options['host'], $this->options['port'], $this->options['timeout']);
        if ('' != $this->options['password']) {
            $this->handler->auth($this->options['password']);
        }
        if (0 != $this->options['select']) {
            $this->handler->select($this->options['select']);
        }
    }

可见TP5的 redis驱动 是基于phpredis的阿, handler 就是实例化的phpredis类, 因此选了哪个驱动,Cache的类自然就是哪些驱动.
所以说如果要使用 TP5的 redis,必须要先安装phpredis扩展.
这里就顺便解析下 redis重写的 set方法

/**
     * 写入缓存
     * @access public
     * @param string    $name 缓存变量名
     * @param mixed     $value  存储数据
     * @param integer   $expire  有效时间(秒)
     * @return boolean
     */
    public function set($name, $value, $expire = null)
    {
        if (is_null($expire)) {
            $expire = $this->options['expire'];
        }
        if ($this->tag && !$this->has($name)) {
            $first = true;
        }
        $key = $this->getCacheKey($name);
        //对数组/对象数据进行缓存处理,保证数据完整性  byron sampson
        $value = (is_object($value) || is_array($value)) ? json_encode($value) : $value;
        if (is_int($expire) && $expire) {
            $result = $this->handler->setex($key, $expire, $value);
        } else {
            $result = $this->handler->set($key, $value);
        }
        isset($first) && $this->setTagItem($key);
        return $result;
    }

原本的phpredis set方法 只能是 普通的键值对, 而重写的set方法现在可以是  键,数组啦,这是非常有用的方法

可以看到实现的 原理是把 数组或者对象 序列化为json, 取值的时候则反序列化成为数组.

到这里我们就基本分析完了一个驱动是如何实现的,首先必须 继承Driver类,实现Driver规定的方法,然后将handler交给Cache类去使用

我们回到Cache类

4.png

可以看到Cache类调用函数的方法基本斗是这样, init()获取 到handler,然后操作handler对象,也就是我们真正的 操作对象,这里就是 phpredis类啦,

当然我们是没办法直接操作 phpredis类的, 只能使用Cache类 的寥寥几种方法,所以有些人不满意,因为队列,集和,哈希都认为没办法使用了,我也在网上看到有些同学 重写TP5的 redis类

其实大可不必, Cache类还是暴露了一个接口给我们的.

我们可以这样

        $res  = Cache::init();        
        $redis = $res->handler();        
        $redis->lpush('test',111);        
        $redis->rpush('test',111);        
        $redis->lpop('test');

获得了 handler 也就是获得了 phpredis,这样就可以随便使用 phpredis原生的方法啦,而且还是单例模式哦, 没有新建对象额外的消耗

本文就到这里结束啦, 如果要知道更多Cache类的使用方法,可以按上文的方式直接看源代码,或者再去查阅官方文档.

虽然没有讲解如何使用,但是分析了 Cache的实现原理有助于提高我们的编程抽象水平, 上文分析源码的方式也同样可以用来分析其他的核心类库.

相关阅读:

ThinkPHP5商城项目实战视频教程课件源码分享

thinkphp5入门该了解的知识

thinkphp5.0学习笔记之数据库的操作

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

418

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

535

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

311

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

77

2025.09.10

thinkphp和laravel哪个简单
thinkphp和laravel哪个简单

对于初学者来说,laravel 的入门门槛较低,更易上手,原因包括:1. 更简单的安装和配置;2. 丰富的文档和社区支持;3. 简洁易懂的语法和 api;4. 平缓的学习曲线。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

374

2024.04.10

thinkphp性能怎么样
thinkphp性能怎么样

thinkphp 是一款高性能的 php 框架,具备缓存机制、代码优化、并行处理和数据库优化等优势。官方性能测试显示,它每秒可处理超过 10,000 个请求,实际应用中被广泛用于京东商城、携程网等大型网站和企业系统。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

324

2024.04.10

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1126

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

192

2025.10.17

俄罗斯Yandex引擎入口
俄罗斯Yandex引擎入口

2026年俄罗斯Yandex搜索引擎最新入口汇总,涵盖免登录、多语言支持、无广告视频播放及本地化服务等核心功能。阅读专题下面的文章了解更多详细内容。

158

2026.01.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
thinkphp3.2实战开发企业网站
thinkphp3.2实战开发企业网站

共52课时 | 14万人学习

THINKPHP 5.0 手册最新版
THINKPHP 5.0 手册最新版

共213课时 | 54.3万人学习

MIP文档手册
MIP文档手册

共47课时 | 26.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号