CI框架缓存的实现原理

?





1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

今天花了点时间看了下CI框架源码缓存的实现,写出来梳理下思路.

1:在CI框架中加载视图文件使用的是$this->load->view();方法,所以从load类库着手,在ci的system文件夹中可以看到Loader.php,这个类库是在Controller.php中被加载的。Loader类中有个方法:

function
view($view, $vars
= array(), $return
= FALSE)//加载视图

{

return $this->_ci_load(array(‘_ci_view‘
=> $view, ‘_ci_vars‘
=> $this->_ci_object_to_array($vars), ‘_ci_return‘
=> $return));

}

调用了自身的一个私有方法_ci_load(),这个方法其中关键部分在:

ob_start();//开启缓存

// If the PHP installation does not support short tags we‘ll

// do a little string replacement, changing the short tags

// to standard PHP echo statements.

if ((bool) @ini_get(‘short_open_tag‘) === FALSE AND config_item(‘rewrite_short_tags‘) == TRUE)

{

echo
eval(‘?>‘.preg_replace("/;*\s*\?>/", "; ?>", str_replace(‘< php echo
file_get_contents_ci_pathbr /> }

else

{

//将视图包含进来

include($_ci_path); // include() vs include_once() allows for multiple views with the same name

}

if (ob_get_level() < $this-<_ci_ob_level + 1)

{

ob_end_flush();

}

else

{

$_ci_CI-<output-<append_output(ob_get_contents());//获取缓存,调用了output类中的append_output方法将缓存的内容放到了output类的全局变量final_output中,供后面使用。

@ob_end_clean();

}

2:CI框架中设置缓存的方法是$this-<output-<cache(n)//n是分钟数

打开system/core/Output.php在里面有个cache方法:

function
cache($time)

{

$this-<cache_expiration = ( ! is_numeric($time)) ? 0 : $time;

//output类中变量cache_expiration赋上缓存时间

return
$this;

}

3:打开system/core/Codeigniter.php这个核心文件。可以看到如下代码:

$OUT =& load_class(‘Output‘, ‘core‘);//实例化output类

// 调用钩子 cache_override hook

if ($EXT->_call_hook(‘cache_override‘) === FALSE)//如果没有设置这个缓存钩子就使用默认的_display_cache方法

{

if ($OUT->_display_cache($CFG, $URI) == TRUE)//将config,uri类的对象传入

{

exit;//如果调用缓存成功就会直接显示页面中断程序,不会加载实例化下面的类,进行一些请求,这就是缓存的好处;

}

}

4:找到Output.php类中的私有方法_display_cache($CFG, $URI):

function
_display_cache(&$CFG, &$URI)

{

//是否在配置文件中定义了缓存路径,如果没有是用系统默认的cache文件夹作为缓存目录

$cache_path
= ($CFG->item(‘cache_path‘) == ‘‘) ? APPPATH.‘cache/‘
: $CFG->item(‘cache_path‘);

// 构造文件路径。文件名是 URI 的 md5 值

$uri = $CFG->item(‘base_url‘).

$CFG->item(‘index_page‘).

$URI->uri_string;//这是请求的页面的控制器/方法/参数那一串字符

$filepath
= $cache_path.md5($uri);

// 判断文件是否存在

if ( ! @file_exists($filepath))

{

return
FALSE;//到了这里就中断了,而是按照正常的向服务器请求页面内容,下面的return false同理

}

if ( ! $fp = @fopen($filepath, FOPEN_READ))

{

return
FALSE;

}

flock($fp, LOCK_SH);//读取文件前给文件加个共享锁

$cache
= ‘‘;

if (filesize($filepath) > 0)

{

$cache
= fread($fp, filesize($filepath));

}

flock($fp, LOCK_UN);//释放锁

fclose($fp);

// 匹配内嵌时间戳

if ( ! preg_match("/(\d+TS--->)/", $cache, $match))

{

return
FALSE;

}

// Has the file expired? If so we‘ll delete it.

// 文件过期了,就删掉

if (time() >= trim(str_replace(‘TS--->‘, ‘‘, $match[‘1‘])))

{

if (is_really_writable($cache_path))

{

@unlink($filepath);

log_message(‘debug‘, "Cache file has expired. File deleted");

return
FALSE }

// Display the cache

// 显示缓存,到了这里说明有缓存文件并且缓存文件没过期,然后执行_display方法

$this->_display(str_replace($match[‘0‘], ‘‘, $cache));

log_message(‘debug‘, "Cache file is current. Sending it to browser.");

return
TRUE;

}

5:找到Output方法中的_display($output=‘‘)方法,这个 方法有两处调用了,1个是在上述的_display_cache中,将缓存文件中的内容取出赋于$output变量然后传入_display($output=‘‘)中,这时候只会执行_display中的:

//$CI 对象不存在,我们就知道我们是在处理缓存文件,所以简单的输出和退出

if ( ! isset($CI))

{

echo
$output;//直接将缓存输出,返回ture中断codeigniter继续执行

log_message(‘debug‘, "Final output sent to browser");

log_message(‘debug‘, "Total execution time: ".$elapsed);

return
TRUE;

}

第二处调用是,当if
($OUT->_display_cache($CFG, $URI) == TRUE)这个判断不成立codeigniter向下执行,

先后实例化了一些系统核心类,以及url中请求的控制器方法等.最后执行一个钩子:

// 调用 display_override hook

if ($EXT->_call_hook(‘display_override‘) === FALSE)

{

$OUT->_display();

}

这时候执行这个方法是无缓存的情况下. 这时候$output为空所以执行了:

// 设置输出数据

if ($output == ‘‘)

{

$output
=& $this->final_output;//这就是在Loader中设置的输出缓存.

}

接下来如果执行了$this->output->cache()方法设置了$this->cache_expiration 参数且没有缓存文件时:

// 启用 cache 时,$CI 没有 _output 函数时,调用 $this->_write_cache,写缓存文件

if ($this->cache_expiration > 0 && isset($CI) && ! method_exists($CI, ‘_output‘))

{

$this->_write_cache($output);

}

_write_cache($output)方法如下:

function
_write_cache($output)

{

$CI
=& get_instance();

$path
= $CI->config->item(‘cache_path‘);

$cache_path
= ($path == ‘‘) ? APPPATH.‘cache/‘
: $path;

// $cache_path 是目录并且可写

if ( ! is_dir($cache_path) OR ! is_really_writable($cache_path))

{

log_message(‘error‘, "Unable to write cache file: ".$cache_path);

return;

}

$uri
= $CI->config->item(‘base_url‘).

$CI->config->item(‘index_page‘).

$CI->uri->uri_string();

$cache_path
.= md5($uri);

if ( ! $fp = @fopen($cache_path, FOPEN_WRITE_CREATE_DESTRUCTIVE))

{

log_message(‘error‘, "Unable to write cache file: ".$cache_path);

return;

}

// 加个时间戳,指示过期时间

$expire
= time() + ($this->cache_expiration * 60);

if (flock($fp, LOCK_EX))//写入前先加个独占锁

{

fwrite($fp, $expire.‘TS--->‘.$output);

flock($fp, LOCK_UN);//写完解锁

}

else

{

log_message(‘error‘, "Unable to secure a file lock for file at: ".$cache_path);

return;

}

fclose($fp);

@chmod($cache_path, FILE_WRITE_MODE);

log_message(‘debug‘, "Cache file written: ".$cache_path);

}

写完缓存后会进行一系列处理比如设置header等 最后输出$output:

if (method_exists($CI, ‘_output‘))

{

$CI->_output($output);

}

else

{

echo
$output; // Send it to the browser!

}

总结:CI的缓存是在要输出的页面设置ob_start(),使用ob_get_contents()获取缓存内容,然后通过判断设置中

是否设置缓存.如果设置了则将缓存将页面的url地址进行MD5哈希作为缓存文件名创建之,然后将(当前时间+设置的缓存时间)+一个特殊符号+内容写到 缓存文件中,下次访问时候将访问的url进行MD5查找这个缓存文件,如果没有则再创建.有则取出其中的内容,分离出过期时间和内容,判断时间是否过期, 如果过期则丢弃内容,继续进行请求,如果没过期直接取出内容输出到页面,中断执行。CI将这一套缓存机制用面向对象的方法写到了框架中,使用起来很方便。 CI默认的这种缓存方法是缓存整个页面。但有时候只要缓存页面中不变的元素header和footer比较好,CI中还有钩子的机制,可以自己设置缓存的 方法替换其中的_display_cache()方法。具体的可以看手册

CI框架缓存的实现原理,码迷,mamicode.com

时间: 2024-10-10 20:07:36

CI框架缓存的实现原理的相关文章

CI框架学习之六 ( 数据库查询缓存优化 )

CI框架中有个比较好的查询优化,就是数据库缓存优化 1.开启缓存 //在application/config.php中开启 $db['default']['cache_on'] = TRUE; //在application/config.php中开启 $db['default']['cachedir'] = './cache'; //并在对应的目录中加一个可写缓存目录cache 2. 在对应的查询中开启缓存语句 // 打开缓存开关 $this->db->cache_on(); $query =

**【ci框架】精通CodeIgniter框架

http://blog.csdn.net/yanhui_wei/article/details/25803945 一.大纲 [php] view plaincopy 1.codeigniter框架的授课内容安排 2.codeigniter框架的简介 |-----关于框架的概念 |-----使用CI框架的好处 |-----为什么选择CI框架 3.codeigniter框架的具体安装步骤 |-----官网下载:http://www.codeigniter.com/ |-----httpd.conf配

CI框架大纲总结

一.大纲 [php] view plaincopy 1.codeigniter框架的授课内容安排 2.codeigniter框架的简介 |-----关于框架的概念 |-----使用CI框架的好处 |-----为什么选择CI框架 3.codeigniter框架的具体安装步骤 |-----官网下载:http://www.codeigniter.com/ |-----httpd.conf配置文件中rewrite重写机制的开启 |-----httpd.conf配置文件虚拟主机的开启 |-----http

CI框架源码阅读笔记3 全局函数Common.php

从本篇开始,将深入CI框架的内部,一步步去探索这个框架的实现.结构和设计. Common.php文件定义了一系列的全局函数(一般来说,全局函数具有最高的加载优先权,因此大多数的框架中BootStrap引导文件都会最先引入全局函数,以便于之后的处理工作). 打开Common.php中,第一行代码就非常诡异: if ( ! defined('BASEPATH')) exit('No direct script access allowed'); 上一篇(CI框架源码阅读笔记2 一切的入口 index

CI框架剖析一

CodeIgniter 是一个小巧但功能强大的 PHP 框架,作为一个简单而"优雅"的工具包,它可以为开发者们建立功能完善的 Web 应用程序.本人使用CI框架有一段时间了,现在决定把该框架源码剖析一遍,理解其构架的用意与精妙之处.分析完所有的源码后,我才来总结CI框架的优缺点,以及适用于哪些场景开发. 目前CI最新的版本是 3.1.4, 4.0版本也即将发布.我们先分析3.1.4版本,然后再看看4.0有哪些重大突破. 首先是查看根目录下index.php文件了,主要定义了几个常量:

CI框架源码阅读笔记1 - 环境准备、基本术语和框架流程

最开始使用CI框架的时候,就打算写一个CI源码阅读的笔记系列,可惜虎头蛇尾,一直没有行动.最近项目少,总算是有了一些时间去写一些东西.于是准备将之前的一些笔记和经验记录下来,一方面权作备忘,另一方面时刻提醒自己:借鉴和学习才有出路,忘记过去意味着背叛! 基本术语说明 在本文开始之前,有必要对文中反复出现的术语做一个简单的说明,如果你对这一部分已经熟谙,完全可以略过.本文中反复出现和提及的术语包括: 前端控制器(Front Controller): 用于集中控制用户的所有请求的组件,将用户的请求发

php CI框架基础知识

一. CI框架的MVC导图 二. CI框架目录文件介绍 (1)index.php  单入口         整个框架对外暴露的唯一访问文件 (2)application  应用文件(放置用户信息,用户控制器.用户模板等) application/cache            --->   缓存 application/config            --->   配置文件 application/controllers        --->   控制器 application/

CI框架源代码阅读笔记6 扩展钩子 Hook.php

CI框架同意你在不改动系统核心代码的基础上加入或者更改系统的核心功能(如重写缓存.输出等). 比如,在系统开启hook的条件下(config.php中$config['enable_hooks'] = TRUE;).通过加入特定的钩子,能够让系统在特定的时刻触发特定的脚本: $hook['post_system'] = array( 'class' => 'frameLog', 'function' => 'postLog', 'filename' => 'post_system.php

CI框架浅析(全篇)

业余花了点时间看看CodeIgniter框架(简称CI),CI目前的稳定版本是 3.X,4.0版本已经出来了,但还在测试中,所以我分析的还是 3.x 版本. CI是一个很轻便的框架,整个下载包也就2M多,而且使用起来方便快捷,适用于一些简单的功能开发,以及做app 接口. 该框架整个流程图如下: li.li1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px "Hannotate SC" } span.s1 { } span.s2 { }