php开发指南:缓存详解

 更新时间:2016年11月25日 15:05  点击:2276
本文章来介绍一下关于php 缓存一些基本常识,有需要的朋友可参考一上。

我们可以在HTML页面利用meta tag和PHP程序中通过header来控制.例如:

 代码如下 复制代码
    <?php
    header('Cache-Control:max-age=86400, must-revalidate');//24小时
    header('Last-Modified:'.gmdate('D, d M Y H:i:s').'GMT');
    header('Expires:'.gmdate('D, d M Y H:i:s', time() + '86400').'GMT');
    echo '我不刷新';再写个HTML文件c.htm:<html>
    <body>
        haha,<a href=cache.php>go</a>
    </body>
</html>

     我们请求127.1/c.htm,点击链接,然后利用浏览器的回退按钮,返回c.htm,再点击链接,如下图左所示,我们发现,当添加了缓存指令后,我们无论如何来回后退和点击链接,下面的网络请求URL这一条始终为灰色,表示浏览器并没有发起实际的网络请求,而是直接调用了存储在用户电脑中的缓存页,除非缓存时间过期,在这期间,即使是实际内容改变了,浏览器也不会去重新读取我们在服务器上的资源。你可以把echo的那一句修改后,再点击,会发现网络请求仍然为灰色。在这种情况下,只有以下三种情况浏览器才会去更新缓存:
(1)缓存到期
(2)缓存被清除;
(3)F5或 ctrl+F5强制刷新。(这一点各种浏览器处理可能存在差异,我的测试环境是firefox 4)  
    当我们屏蔽上面的header指令或者改用如下代码时//告诉客户端浏览器不使用缓存,HTTP 1.1 协议

 代码如下 复制代码
header("Cache-Control: no-cache, must-revalidate");

//告诉客户端浏览器不使用缓存,兼容HTTP 1.0 协议

 代码如下 复制代码
header("Pragma: no-cache");

c1.pngc2.png

      浏览器就会在每次请求时都去服务器上读取资源。如下面右边的图所示。    在这里,我们可以大致了解下浏览器对页面的缓存处理。很容易,我们就能联想出其使用场景,有时候我们需要它缓存,有时候又不需要,你可以根据场景来使用。不过,浏览器的缓存作用是很微小的,但能省一点算一点。有时候,浏览器的缓存是很厉害的,需要我们强制刷新才能见效,比如JS文件,有时你更改了,即使刷新也是不会更改的。另,除了可以在代码中设置页面缓存,也可以在APACHE等服务器上配置,特别是静态资源,加上缓存可以有效减少不必要的请求。
    又有时,我们通常会看到<script src="link.js?d=1923454332"></script>这样的代码,在JS文件后加上问号的那一串并没有实际意义,只是为了避免JS被缓存,给JS文件加一个版本号,通常用时间戳做标记。这样浏览器就不会缓存我们的JS文件了。
    既然前端页面缓存的目的是为了减少请求,那我马上想到了另一个思路,那就是压缩数据。通过使用一些工具,可以对CSS和JS代码进行压缩。比如jquery的使用版就是经过压缩的,往往这个压缩比例还很大。通常使用jsmin,jspacker进行压缩,具体工具可以到网上搜索下。

array_merge() 函数把两个或多个数组合并为一个数组。

如果键名有重复,该键的键值为最后一个键名对应的值(后面的覆盖前面的)。如果数组是数字索引的,则键名会以连续方式重新索引。

注释:如果仅仅向 array_merge() 函数输入了一个数组,且键名是整数,则该函数将返回带有整数键名的新数组,其键名以 0 开始进行重新索引。

 代码如下 复制代码


<?php
$a=array(3=>"Horse",4=>"Dog");
print_r(array_merge($a));
?>


 

将一个或多个数组的单元合并起来,一个数组中的值附加在前一个数组的后面。返回作为结果的数组。

如果输入的数组中有相同的字符串键名,则该键名后面的值将覆盖前一个值。然而,如果数组包含数字键名,后面的值将不会覆盖原来的值,而是附加到后面。

如果只给了一个数组并且该数组是数字索引的,则键名会以连续方式重新索引。

实例如下:

 代码如下 复制代码

$face = array("J","Q","K","A");
$numbered = array("2","3","4","5","6","7","8","9");
$cards = array_merge($face, $numbered);
shuffle($cards);
print_r($cards);


 

这将返回如下所示的结果,

 

 代码如下 复制代码
Array ( [0] => A [1] => 4 [2] => 9 [3] => 3 [4] => K [5] => 7 [6] => 5 [7] => Q [8] => 6 [9] => 8 [10] => 2 [11] => J )

递归追加数组
array_merge_recursive()函数与array_merge()相同,可以将两个或多个数组合并在一起,形成一个联合的数组.两者之间 的区别在于,当某个输入数组中的某个键己经存在于结果数组中时该函数会采取不同的处理方式.array_merge()会覆盖前面存在的键/值对,替换为 当前输入数组中的键/值对,而array_merge_recursive()将把两个值合并在一起,形成一个新的数组,并以原有的键作为数组名。还有一 个数组合并的形式,就是递归追加数组。其形式为:

array array_merge_recursive( array key,array values )

示例如下:

 代码如下 复制代码

<?php
$array1 = array("AA"=>"A","BB"=>"B","CC"=>"C","DD"=>"D");
$array2 = array("AA"=>"1","BB"=>"2","CC"=>"3","DD"=>"4");
$array3 = array("AA"=>"!","BB"=>"@","CC"=>"#","DD"=>"$");
$arrayX = array_merge($array1, $array2, $array3);     //合并数组
print_r($arrayX);
?>

 

连接两个数组

array_combine()函数会得到一个新数组,它由一组提交的键和对应的值组成。其形式为:

array array_merge(array array1,array array2[…,array arrayN])

注意,两个输入数组必须大小相同,不能为空。示例如下:

 代码如下 复制代码

<?php
$array1 = array("AA"=>"A","BB"=>"B","CC"=>"C","DD"=>"D");
$array2 = array("AA"=>"1","BB"=>"2","CC"=>"3","DD"=>"4");
$array3 = array("AA"=>"!","BB"=>"@","CC"=>"#","DD"=>"$");
$arrayX = array_merge($array1, $array2, $array3);     //合并数组
print_r($arrayX);
?>

大家可通常用的microtime()获取页面开始和结束时的时间并相减的话,计算结果是页面运行 所经历的一段时间,但这并不一定是该页面自身运行的时间
 代码如下 复制代码

<?php
//实例:计算页面运行时加载时间
//分析:页面打开时获取一个时间,加载完成时获取一个时间,运行时间即二者之差

//1.自定义函数
function fn(){
 list($a,$b) = explode(' ',microtime()); //获取并分割当前时间戳和微妙数,赋值给变量
 return $a+$b;
}

//2.获取开始时间
$start_time = fn();
//5.加载过程
for($i=0;$i<10000000;$i++){
 // do nothing;
}

//3.获取结束时间
$end_time = fn();

//4.计算差值
echo $end_time-$start_time;

//5.格式化输出
echo '<br />';
$t = $end_time-$start_time;
echo round($t,2);

?>

使用microtime()获取页面开始和结束时的时间并相减的话,计算结果是页面运行
所经历的一段时间,但这并不一定是该页面自身运行的时间。因为可能存在多个PHP脚
本页面共同执行的情况,所以我觉得那个方法是不准确的


下面从网上找到一个关于php中计算页面程序运行时间的实例有需要的朋友可参考一下。

最近写了一个程序运行的时间计算类,供大家参考:

 代码如下 复制代码
class Timer { 
    private $StartTime = 0;//程序运行开始时间
    private $StopTime  = 0;//程序运行结束时间
    private $TimeSpent = 0;//程序运行花费时间
    function start(){//程序运行开始
        $this->StartTime = microtime(); 
    } 
    function stop(){//程序运行结束
        $this->StopTime = microtime(); 
    } 
    function spent(){//程序运行花费的时间
        if ($this->TimeSpent) { 
            return $this->TimeSpent; 
        } else {
         list($StartMicro, $StartSecond) = explode(" ", $this->StartTime);
         list($StopMicro, $StopSecond) = explode(" ", $this->StopTime);
            $start = doubleval($StartMicro) + $StartSecond;
            $stop = doubleval($StopMicro) + $StopSecond;
            $this->TimeSpent = $stop - $start;
            return substr($this->TimeSpent,0,8)."秒";//返回获取到的程序运行时间差
        } 
    } 

$timer = new Timer(); 
$timer->start();
//...程序运行的代码
$timer->stop();
echo "程序运行时间为:".$timer->spent();

再看简化程序 计算页面加载时间

 代码如下 复制代码


<?php
class runtime
{
        var $StartTime = 0;
        var $StopTime = 0;
        function get_microtime()
        {
                list($usec, $sec) = explode(' ', microtime());
                return ((float)$usec (float)$sec);
        }
       
        function start()
        {
                $this->StartTime = $this->get_microtime();
        }
       
        function stop()
        {
                $this->StopTime = $this->get_microtime();
        }
       
        function spent()
        {
                return round(($this->StopTime - $this->StartTime) * 1000, 1);
        }
}

//实例开始
$runtime= new runtime;
$runtime->start();
//你的代码开始
$a = 0;
for($i=0; $i<1000000; $i )
{
        $a = $i;
}
//你的代码结束
$runtime->stop();
echo "页面执行时间: ".$runtime->spent()." 毫秒";
?>

文章介绍了php函数ob_start()、ob_end_clean()、ob_get_contents(),有需要的朋友可参考一下。

下面3个函数的用法

ob_get_contents() - 返回输出缓冲区的内容


ob_get_contents

(PHP 4, PHP 5)

ob_get_contents — 返回输出缓冲区的内容
说明
string ob_get_contents ( void )

只是得到输出缓冲区的内容,但不清除它。
返回值

此函数返回输出缓冲区的内容,或者如果输出缓冲区无效将返回FALSE 。
范例

 代码如下 复制代码

Example #1 A simple ob_get_contents() example
<?php

ob_start();

echo "Hello ";

$out1 = ob_get_contents();

echo "World";

$out2 = ob_get_contents();

ob_end_clean();

var_dump($out1, $out2);
?>

以上例程会输出:

string(6) "Hello "
string(11) "Hello World"

 

ob_flush() - 冲刷出(送出)输出缓冲区中的内容

ob_flush

(PHP 4 >= 4.2.0, PHP 5)

ob_flush — 冲刷出(送出)输出缓冲区中的内容
说明
void ob_flush ( void )

这个函数将送出缓冲区的内容(如果里边有内容的话)。如果想进一步处理缓冲区中的内容,必须在ob_flush()之前调用ob_get_contents() ,因为在调用ob_flush()之后缓冲区内容将被丢弃。

此函数不会销毁输出缓冲区,而像ob_end_flush() 函数会销毁缓冲区。
返回值

没有返回值。


ob_clean() - 清空(擦掉)输出缓冲区


ob_clean

(PHP 4 >= 4.2.0, PHP 5)

ob_clean — 清空(擦掉)输出缓冲区
说明
void ob_clean ( void )

此函数用来丢弃输出缓冲区中的内容。

此函数不会销毁输出缓冲区,而像 ob_end_clean() 函数会销毁输出缓冲区。
返回值

没有返回值。

ob_end_flush() - 冲刷出(送出)输出缓冲区内容并关闭缓冲


ob_end_flush — 冲刷出(送出)输出缓冲区内容并关闭缓冲
说明
bool ob_end_flush ( void )

这个函数将送出最顶层缓冲区的内容(如果里边有内容的话),并关闭缓冲区。如果想进一步处理缓冲区中的内容,必须在ob_end_flush()之前调用 ob_get_contents(),因为在调用ob_end_flush()后缓冲区内容被丢弃。

    Note: 这个函数与ob_get_flush()相似,不同的是ob_get_flush()会把缓冲区中的内容作为字符串返回。

返回值

成功时返回 TRUE, 或者在失败时返回 FALSE. 错误的原因首先是,在调用时没有一个起作用的缓冲区,或者是因为某些原因缓冲区不能被删除(可能对特殊缓冲区而言)。
错误/异常

如果函数失败了,将引发一个E_NOTICE异常。
更新日志

版本  说明
4.2.0  添加了布尔返回值。

范例

Example #1 ob_end_flush() example

下面的例子给出了一种送出缓冲区内容并关闭所有输出缓冲区的容易的方法:

 代码如下 复制代码
<?php
  while (@ob_end_flush());
?>

ob_end_clean() - 清空(擦除)缓冲区并关闭输出缓冲

ob_end_clean — 清空(擦除)缓冲区并关闭输出缓冲
说明
bool ob_end_clean ( void )

此函数丢弃最顶层输出缓冲区的内容并关闭这个缓冲区。如果想要进一步处理缓冲区的内容,必须在ob_end_clean()之前调用ob_get_contents(),因为当调用ob_end_clean()时缓冲区内容将被丢弃。
返回值

成功时返回 TRUE, 或者在失败时返回 FALSE. 错误的原因首先是,在调用时没有一个起作用的缓冲区,或者是因为某些原因缓冲区不能被删除(可能对特殊缓冲区而言)。
错误/异常

如果函数失败了,将引发一个E_NOTICE异常。
更新日志

版本  说明
4.2.0  添加了布尔返回值。

范例

下面的例子给出了一种去除所有输出缓冲区的方法:

 代码如下 复制代码

Example #1 ob_end_clean() example
<?php
ob_start();
echo 'Text that won't get displayed.';
ob_end_clean();
?>

flush() - 刷新输出缓冲    

通常是ob_flush();flush()同时一起使用
使用ob_start()把输出那同输出到缓冲区,而不是到浏览器。
然后用ob_get_contents得到缓冲区的数据。

ob_start()在服务器打开一个缓冲区来保存所有的输出。所以在任何时候使用echo ,输出都将被加入缓冲区中,直到程序运行结束或者使用ob_flush()来结束。然后在服务器中缓冲区的内容才会发送到浏览器,由浏览器来解析显示。

函数ob_end_clean 会清除缓冲区的内容,并将缓冲区关闭,但不会输出内容。
此时得用一个函数ob_get_contents()在ob_end_clean()前面来获得缓冲区的内容。
这样的话, 能将在执行ob_end_clean()前把内容保存到一个变量中,然后在ob_end_clean()后面对这个变量做操作。

最近在使用php的mongo 扩展进行数据统计计算,其中有一个时间戳字段,由于精确到了毫秒,长度有13位,但由于开始的时候是以字符串的形式存储:
 代码如下 复制代码

 


{ "_id" : ObjectId("504eea97e4b023cf38e34039"), "in_ts" : NumberLong("1347349143699"), "log" : { "guid" : "4D1F3079-7507-F4B0-E7AF-5432D5D8229D", "p" : "View_Prop_YepPage_Zheng", "cid" : "11", "url" : "http://shanghai.haozu.com/rental/broker/n/10481780", "rfpn" : "Listing_V2_IndexPage_All", "site" : "haozu", "agent" : "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)", "stamp" : "1347349162159", "cip" : "116.226.70.44", "referer" : "http://shanghai.haozu.com/shop/1464934/", "cstamp" : "1347349323125", "sessid" : "FA798056-F9E7-F961-41E0-CC95C850FA47", "uguid" : "C00FF55B-3D3D-4B31-4318-12345B0DBE64", "pn" : "View_Prop_YepPage_Zheng", "cstparam" : { "proId" : NumberLong(10481780), "brokerId" : "326792", "tradeType" : "2", "userType" : "0", "channel" : "site", "entry" : "1", "COMMID" : "1666" } }, "out_ts" : NumberLong("1347349466083"), "rule" : 0, "status" : "ok", "txid" : 0 }

后来改成数字格式:

 

 代码如下 复制代码

{ "_id" : ObjectId("504eea97e4b023cf38e34039"), "in_ts" : NumberLong("1347349143699"), "log" : { "guid" : "4D1F3079-7507-F4B0-E7AF-5432D5D8229D", "p" : "View_Prop_YepPage_Zheng", "cid" : "11", "url" : "http://shanghai.haozu.com/rental/broker/n/10481780", "rfpn" : "Listing_V2_IndexPage_All", "site" : "haozu", "agent" : "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)", "stamp" : NumberLong("1347349162159"), "cip" : "116.226.70.44", "referer" : "http://shanghai.haozu.com/shop/1464934/", "cstamp" : "1347349323125", "sessid" : "FA798056-F9E7-F961-41E0-CC95C850FA47", "uguid" : "C00FF55B-3D3D-4B31-4318-12345B0DBE64", "pn" : "View_Prop_YepPage_Zheng", "cstparam" : { "proId" : NumberLong(10481780), "brokerId" : "326792", "tradeType" : "2", "userType" : "0", "channel" : "site", "entry" : "1", "COMMID" : "1666" } }, "out_ts" : NumberLong("1347349466083"), "rule" : 0, "status" : "ok", "txid" : 0 }为字符串时,使用下面的查询是正常的

        $query = array ('log.stamp' => array ('$gte' => ‘1347346800000’, '$lt' => ‘1347350400000’));

但是改为数字后,使用下面的查询,死活没有结果,但是直接在mongo客户端直接查询是有结果的:

 

 代码如下 复制代码
 db.haozu_success.find({'log.stamp':{$gte:1347346800000,$lt:1347350400000}})

php手册上也是这么个用法:

 代码如下 复制代码
        $query = array ('log.stamp' => array ('$gte' => 1347346800000, '$lt' => 1347350400000));

花了好大一会找原因,开始时怀疑是php扩展的bug导致,经过一番思考。突然想到可能是类型问题导致,发现手册上有Types 介绍,所以正确的用法如下:

 代码如下 复制代码

        $query = array ('log.stamp' => array ('$gte' => new MongoInt64($time_range['start']), '$lt' => new MongoInt64($time_range['end'])));

另外,在使用mapreduce进行数据统计时,为了防止cursor出现超时异常,还需要设置一下超时时间

 

 代码如下 复制代码
$map = new MongoCode ( '
                function(){
                    var prop_id=this.log.cstparam.proId;
                    var key=this.log.site+prop_id
                    emit(key,{"channel":this.log.site,"prop_id":prop_id,"count":1});
                }
                ' );
        $reduce = new MongoCode ( '
                function(key,emits){
                    var total=0;
                    for(var i in emits){
                        total+=emits[i].count;
                    }
                    return {"channel":emits[0].channel,"prop_id":eval(emits[0].prop_id),"count":total};
                }
                ' );
$this->mongo_db->command ( array ('mapreduce' => $collection_name, 'map' => $map, 'reduce' => $reduce, 'out' => $tmp_result, 'query' => $query),array('timeout'=>self::MONGO_CURSOR_TIMEOUT) );
[!--infotagslink--]

相关文章

  • c#自带缓存使用方法 c#移除清理缓存

    这篇文章主要介绍了c#自带缓存使用方法,包括获取数据缓存、设置数据缓存、移除指定数据缓存等方法,需要的朋友可以参考下...2020-06-25
  • 源码分析系列之json_encode()如何转化一个对象

    这篇文章主要介绍了源码分析系列之json_encode()如何转化一个对象,对json_encode()感兴趣的同学,可以参考下...2021-04-22
  • php中去除文字内容中所有html代码

    PHP去除html、css样式、js格式的方法很多,但发现,它们基本都有一个弊端:空格往往清除不了 经过不断的研究,最终找到了一个理想的去除html包括空格css样式、js 的PHP函数。...2013-08-02
  • IDEA中的clean,清除项目缓存图文教程

    这篇文章主要介绍了IDEA中的clean,清除项目缓存图文教程,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-25
  • index.php怎么打开?如何打开index.php?

    index.php怎么打开?初学者可能不知道如何打开index.php,不会的同学可以参考一下本篇教程 打开编辑:右键->打开方式->经文本方式打开打开运行:首先你要有个支持运行PH...2017-07-06
  • PHP中func_get_args(),func_get_arg(),func_num_args()的区别

    复制代码 代码如下:<?php function jb51(){ print_r(func_get_args()); echo "<br>"; echo func_get_arg(1); echo "<br>"; echo func_num_args(); } jb51("www","j...2013-10-04
  • vscode搭建STM32开发环境的详细过程

    这篇文章主要介绍了vscode搭建STM32开发环境的详细过程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-05-02
  • PHP编程 SSO详细介绍及简单实例

    这篇文章主要介绍了PHP编程 SSO详细介绍及简单实例的相关资料,这里介绍了三种模式跨子域单点登陆、完全跨单点域登陆、站群共享身份认证,需要的朋友可以参考下...2017-01-25
  • iOS蓝牙设备名称缓存问题的解决方法

    这篇文章主要给大家介绍了关于iOS蓝牙设备名称缓存问题的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-12-08
  • 安卓开发之Intent传递Object与List教程

    下面我们一起来看一篇关于 安卓开发之Intent传递Object与List的例子,希望这个例子能够为各位同学带来帮助。 Intent 不仅可以传单个的值,也可以传对象与数据集合...2016-09-20
  • PHP实现创建以太坊钱包转账等功能

    这篇文章主要介绍了PHP实现创建以太坊钱包转账等功能,对以太坊感兴趣的同学,可以参考下...2021-04-20
  • php微信公众账号开发之五个坑(二)

    这篇文章主要为大家详细介绍了php微信公众账号开发之五个坑,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2016-10-02
  • AngularJS实现Model缓存的方式

    这篇文章主要介绍了AngularJS实现Model缓存的方式,分享了多种AngularJS实现Model缓存的方法,感兴趣的小伙伴们可以参考一下...2016-02-05
  • 如何设计一个安全的API接口详解

    在日常开发中,总会接触到各种接口,前后端数据传输接口,第三方业务平台接口,下面这篇文章主要给大家介绍了关于如何设计一个安全的API接口的相关资料,需要的朋友可以参考下...2021-08-12
  • PHP如何通过date() 函数格式化显示时间

    这篇文章主要介绍了PHP如何通过date() 函数格式化显示时间,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-11-13
  • ThinkPHP使用心得分享-ThinkPHP + Ajax 实现2级联动下拉菜单

    首先是数据库的设计。分类表叫cate.我做的是分类数据的二级联动,数据需要的字段有:id,name(中文名),pid(父id). 父id的设置: 若数据没有上一级,则父id为0,若有上级,则父id为上一级的id。数据库有内容后,就可以开始写代码,进...2014-05-31
  • @CacheEvict + redis实现批量删除缓存

    这篇文章主要介绍了@CacheEvict + redis实现批量删除缓存方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-10-12
  • python怎么删除缓存文件

    在本篇文章里小编给大家整理的是一篇关于python删除缓存文件方法,需要的朋友们可以学习下。...2020-07-19
  • Nodejs下DNS缓存问题浅析

    本文给大家一起探讨nodejs下dns的缓存问题,本文给大家介绍的非常详细,感兴趣的朋友一起看看吧...2016-11-22
  • vue项目中禁用浏览器缓存配置案例

    这篇文章主要介绍了vue项目中禁用浏览器缓存配置案例,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下...2021-09-12