澳门新浦京娱乐游戏PHP输出缓存ob系列函数详解_php技巧_脚本之家

本文由码农网 –
小峰原创翻译,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划!

ob的基本原则:如果ob缓存打开,则echo的数据首先放在ob缓存。如果是header信息,直接放在程序缓存。当页面执行到最后,会把ob缓存的数据放到程序缓存,然后依次返回给浏览器。下面我说说ob的基本作用:
1)防止在浏览器有输出之后再使用setcookie或session_start()等发送头文件的函数造成的错误。其实这样的用法少用为好,养成良好的代码习惯。
2)捕捉对一些不可获取的函数的输出,比如phpinfo()会输出一大堆的HTML,但是我们无法用一个变量例如$info=phpinfo对输出的内容进行处理,例如进行gzip压缩,例如进行简繁转换,例如进行一些字符串替换。
4)生成静态文件,其实就是捕捉整页的输出,然后存成文件。经常在生成HTML,或者整页缓存中使用。

今天我们要介绍一些关于改善和优化PHP代码的提示和技巧。请注意,这些PHP技巧适用于初学者,而不是那些已经在使用MVC框架的人。

对于刚才说的第三点中的GZIP压缩,可能是很多人想用,却没有真用上的,其实稍稍修改下代码,就可以实现页面的gzip压缩。复制代码
代码如下:ob_start;要缓存的内容没错,加一个ob_gzhandler这个回调函数就可以了,不过这么做有些小问题,一是需要zlib支持,二是没有判断浏览器是否支持gzip(现在好像都支持,iphone浏览器好像都支持了)。以前的做法是判断一下浏览器是否支持gzip,然后用第三方的gzip函数来压缩ob_get_contents()
的内容,最后echo。

澳门新浦京娱乐游戏 1

一、ob系列函数中常用函数集锦复制代码
代码如下:ob_start();
//打开一个输出缓冲区,所有的输出信息不再直接发送到浏览器,而是保存在输出缓冲区里面。

1.不要使用相对路径,要定义一个根路径

这样的代码行很常见:

require_once('../../lib/some_class.php');

这种方法有很多缺点:

  • 它首先搜索php包括路径中的指定目录,然后查看当前目录。因此,会检查许多目录。
  • 当一个脚本被包含在另一个脚本的不同目录中时,它的基本目录变为包含脚本的目录。
  • 另一个问题是,当一个脚本从cron运行时,它可能不会将它的父目录作为工作目录。

所以使用绝对路径便成为了一个好方法:

define('ROOT' , '/var/www/project/');
require_once(ROOT . '../../lib/some_class.php');

//rest of the code

这就是一个绝对路径,并且会一直保持不变。但是,我们可以进一步改善。目录/var/www/project可以变,那么我们每次都要改吗?

不,使用魔术常量如__FILE__可以让它变得可移植。请仔细看:

//suppose your script is /var/www/project/index.php
//Then __FILE__ will always have that full path.

define('ROOT' , pathinfo(__FILE__, PATHINFO_DIRNAME));
require_once(ROOT . '../../lib/some_class.php');

//rest of the code

所以现在,即使你将项目转移到一个不同的目录,例如将其移动到一个在线的服务器上,这些代码不需要更改就可以运行。

ob_clean(); //删除内部缓冲区的内容,不关闭缓冲区;
//删除内部缓冲区的内容,关闭缓冲区;
//返回内部缓冲区的内容,关闭缓冲区。相当于执行
ob_get_contentsob_flush();
//发送内部缓冲区的内容到浏览器,删除缓冲区的内容,不关闭缓冲区。ob_end_flush();
//发送内部缓冲区的内容到浏览器,删除缓冲区的内容,关闭缓冲区。ob_get_flush();
//返回内部缓冲区的内容,并关闭缓冲区,再释放缓冲区的内容。相当于ob_end_flush;
//将ob_flush释放出来的内容,以及不在PHP缓冲区中的内容,全部输出至浏览器;刷新内部缓冲区的内容,并输出。

2.不使用require,包括require_once或include_once

你的脚本上可能会包括各种文件,如类库,实用程序文件和辅助函数等,就像这些:

require_once('lib/Database.php');
require_once('lib/Mail.php');

require_once('helpers/utitlity_functions.php');

这相当粗糙。代码需要更加灵活。写好辅助函数可以更容易地包含东西。举个例子:

function load_class($class_name)
{
    //path to the class file
    $path = ROOT . '/lib/' . $class_name . '.php');
    require_once( $path ); 
}

load_class('Database');
load_class('Mail');

看到区别了吗?很明显。不需要任何更多的解释。

你还可以进一步改善:

function load_class($class_name)
{
    //path to the class file
    $path = ROOT . '/lib/' . $class_name . '.php');

    if(file_exists($path))
    {
        require_once( $path ); 
    }
}

这样做可以完成很多事情:

  • 为同一个类文件搜索多个目录。
  • 轻松更改包含类文件的目录,而不破坏任何地方的代码。
  • 使用类似的函数用于加载包含辅助函数、HTML内容等的文件。

ob_get_contents(); //返回缓冲区的内容,不输出。ob_get_length();
//返回内部缓冲区的长度,如果缓冲区未被激活,该函数返回FALSE。ob_get_level();
//Return the nesting level of the output buffering
mechanism.ob_get_status(); //Get status of output buffers.

3.在应用程序中维护调试环境

在开发过程中,我们echo数据库查询,转储创造问题的变量,然后一旦问题被解决,我们注释它们或删除它们。但让一切留在原地可提供长效帮助。

在开发计算机上,你可以这样做:

define('ENVIRONMENT' , 'development');

if(! $db->query( $query )
{
    if(ENVIRONMENT == 'development')
    {
        echo "$query failed";
    }
    else
    {
        echo "Database error. Please contact administrator";
    }    
}

并且在服务器上,你可以这样做:

define('ENVIRONMENT' , 'production');

if(! $db->query( $query )
{
    if(ENVIRONMENT == 'development')
    {
        echo "$query failed";
    }
    else
    {
        echo "Database error. Please contact administrator";
    }    
}

ob_implicit_flush();
//打开或关闭绝对刷新,默认为关闭,打开后ob_implicit_flush,所谓绝对刷新,即当有输出语句被执行时,便把输出直接发送到浏览器,而不再需要调用flush()或等到脚本结束时才输出。

4.通过会话传播状态消息

状态消息是那些执行任务后生成的消息。

<?php
if($wrong_username || $wrong_password)
{
    $msg = 'Invalid username or password';
}
?>
<html>
<body>

<?php echo $msg; ?>

<form>
...
</form>
</body>
</html>

这样的代码很常见。使用变量来显示状态信息有一定的局限性。因为它们无法通过重定向发送(除非你将它们作为GET变量传播给下一个脚本,但这非常愚蠢)。而且在大型脚本中可能会有多个消息等。

最好的办法是使用会话来传播(即使是在同一页面上)。想要这样做的话在每个页面上必须得有一个session_start。

function set_flash($msg)
{
    $_SESSION['message'] = $msg;
}

function get_flash()
{
    $msg = $_SESSION['message'];
    unset($_SESSION['message']);
    return $msg;
}

在你的脚本中:

<?php
if($wrong_username || $wrong_password)
{
    set_flash('Invalid username or password');
}
?>
<html>
<body>

Status is : <?php echo get_flash(); ?>
<form>
...
</form>
</body>
</html>

ob_gzhandler
//ob_start回调函数,用gzip压缩缓冲区的内容。ob_list_handlers //List
all output handlers in useoutput_add_rewrite_var //Add URL rewriter
valuesoutput_reset_rewrite_vars //Reset URL rewriter values

5.让函数变得灵活

function add_to_cart($item_id , $qty)
{
    $_SESSION['cart'][$item_id] = $qty;
}

add_to_cart( 'IPHONE3' , 2 );

当添加单一条目时,使用上面的函数。那么当添加多个条目时,就得创建另一个函数吗?NO。只要让函数变得灵活起来使之能够接受不同的参数即可。请看:

function add_to_cart($item_id , $qty)
{
    if(!is_array($item_id))
    {
        $_SESSION['cart'][$item_id] = $qty;
    }

    else
    {
        foreach($item_id as $i_id => $qty)
        {
            $_SESSION['cart'][$i_id] = $qty;
        }
    }
}

add_to_cart( 'IPHONE3' , 2 );
add_to_cart( array('IPHONE3' => 2 , 'IPAD' => 5) );

好了,现在同样的函数就可以接受不同类型的输出了。以上代码可以应用到很多地方让你的代码更加灵活。

这些函数的行为受php_ini设置的影响:output_buffering
//该值为ON时,将在所有脚本中使用输出控制;若该值为一个数字,则代表缓冲区的最大字节限制,当缓存内容达到该上限时将会自动向浏览器输出当前的缓冲区里的内容。output_handler
//该选项可将脚本所有的输出,重定向到一个函数。例如,将 output_handler
设置为 mb_output_handler()
时,字符的编码将被修改为指定的编码。设置的任何处理函数,将自动的处理输出缓冲。implicit_flush
//作用同ob_implicit_flush,默认为Off。

6.省略结束的php标签,如果它是脚本中的最后一行

我不知道为什么很多博客文章在谈论php小技巧时要省略这个技巧。

<?php

echo "Hello";

//Now dont close this tag

这可以帮助你省略大量问题。举一个例子:

类文件super_class.php

<?php
class super_class
{
    function super_function()
    {
        //super code
    }
}
?>
//super extra character after the closing tag

现在看index.php

require_once('super_class.php');

//echo an image or pdf , or set the cookies or session data

你会得到发送错误的Header。为什么呢?因为“超级多余字符”,所有标题都去处理这个去了。于是你得开始调试。你可能需要浪费很多时间来寻找超级额外的空间。

因此要养成省略结束标签的习惯:

<?php
class super_class
{
    function super_function()
    {
        //super code
    }
}

//No closing tag

这样更好。

二、实例讲解

7.在一个地方收集所有输出,然后一次性输出给浏览器

这就是所谓的输出缓冲。比方说,你从不同的函数得到像这样的内容:

function print_header()
{
    echo "<div id='header'>Site Log and Login links</div>";
}

function print_footer()
{
    echo "<div id='footer'>Site was made by me</div>";
}

print_header();
for($i = 0 ; $i < 100; $i++)
{
    echo "I is : $i <br />';
}
print_footer();

其实你应该先在一个地方收集所有输出。你可以要么将它存储于函数中的变量内部,要么使用ob_start和ob_end_clean。所以,现在应该看起来像这样

function print_header()
{
    $o = "<div id='header'>Site Log and Login links</div>";
    return $o;
}

function print_footer()
{
    $o = "<div id='footer'>Site was made by me</div>";
    return $o;
}

echo print_header();
for($i = 0 ; $i < 100; $i++)
{
    echo "I is : $i <br />';
}
echo print_footer();

那么,为什么你应该做输出缓冲呢:

  • 你可以在将输出发送给浏览器之前更改它,如果你需要的话。例如做一些str_replaces,或者preg_replaces,又或者是在末尾添加一些额外的html,例如profiler/debugger输出。
  • 发送输出给浏览器,并在同一时间做php处理并不是好主意。你见过这样的网站,它有一个Fatal
    error在侧边栏或在屏幕中间的方框中吗?你知道为什么会出现这种情况吗?因为处理过程和输出被混合在了一起。

1、使 header() 函数前可以有echo代码Output Control
函数可以让你自由控制脚本中数据的输出。它非常地有用,特别是对于:当你想在数据已经输出后,再输出文件头的情况。输出控制函数不对使用
header,发送的文件头信息产生影响,只对那些类似于 echo() 和 PHP
代码的数据块有作用。 复制代码
代码如下:ob_start(); //打开缓冲区 echo “Hellon”; //输出 header;
//把浏览器重定向到index.php ob_end_flush();
//输出全部内容到浏览器所有对header()函数有了解的人都知道,这个函数会发送一段文件头给浏览器,但是如果在使用这个函数之前已经有了任何输出就会提示出错。如果我们去掉第一行的ob_start(),再执行此程序,我们会发现得到了一条错误提示:”Header
had all ready send
by”!但是加上ob_start,就不会提示出错,原因是当打开了缓冲区,echo后面的字符不会输出到浏览器,而是保留在服务器,直到你使用flush或者ob_end_flush才会输出,所以并不会有任何文件头输出的错误!2、保存
phpinfo() 函数的输出
复制代码
代码如下:ob_start; //使用phpinfo函数 $info = ob_get_contents();
//得到缓冲区的内容并且赋值给$info $file = fopen; //打开文件info.txt
fwrite; //写入信息到info.txt fclose;
//关闭文件info.txt3、静态模版技术所谓静态模版技术就是通过某种方式,使得用户在client端得到的是由PHP产生的html页面。如果这个html页面不会再被更新,那么当另外的用户再次浏览此页面时,程序将不会再调用PHP以及相关的数据库,对于某些信息量比较大的网站,例如sina、163、sohu。类似这种的技术带来的好处是非常巨大的。
复制代码 代码如下:ob_start();
//打开缓冲区php页面的全部输出 $content = ob_get_contents();
//取得php页面输出的全部内容 $fp = fopen(“output00001.html”, “w”);
//创建一个文件,并打开,准备写入 fwrite;
//把php页面的内容全部写入output00001.html,然后……
fclose;三、输出缓存句柄ob_gzhandlerPHP4.0.4有一个新的输出缓存句柄ob_gzhandler,它与前面的类相似,但用法不同。使用ob_gzhandler时要在php.ini中加入的内容如下:
复制代码 代码如下:output_handler =
ob_gzhandler;这行代码使得PHP激活输出缓存,并压缩它发送出去的所有内容。

8.当输出非HTML内容时,通过header发送正确的mime类型

请看一些XML。

$xml = '<?xml version="1.0" encoding="utf-8" standalone="yes"?>';
$xml = "<response>
  <code>0</code>
</response>";

//Send xml data
echo $xml;

工作正常。但它需要一些改进。

$xml = '<?xml version="1.0" encoding="utf-8" standalone="yes"?>';
$xml = "<response>
  <code>0</code>
</response>";

//Send xml data
header("content-type: text/xml");
echo $xml;

请注意header行。这行代码告诉浏览器这个内容是XML内容。因此,浏览器能够正确地处理它。许多JavaScript库也都依赖于header信息。

JavaScript,css,jpg图片,png图像也是一样:

JavaScript

header("content-type: application/x-javascript");
echo "var a = 10";

CSS

header("content-type: text/css");
echo "#div id { background:#000; }"

如果由于某种原因你不想在php.ini中加上这行代码,你还可以通过PHP源文件所在目录的.htaccess文件改变默认的服务器行为,语法如下:
复制代码 代码如下:php_value
output_handler ob_gzhandler或者是从PHP代码调用,如下所示:

9.为MySQL连接设置正确的字符编码

曾碰到过unicode/utf-8字符被正确地存储在mysql表的问题,phpmyadmin也显示它们是正确的,但是当你使用的时候,你的网页上却并不能正确地显示。里面的奥妙在于MySQL连接校对。

$host = 'localhost';
$username = 'root';
$password = 'super_secret';

//Attempt to connect to database
$c = mysqli_connect($host , $username, $password);

//Check connection validity
if (!$c) 
{
    die ("Could not connect to the database host: <br />". mysqli_connect_error());
}

//Set the character set of the connection
if(!mysqli_set_charset ( $c , 'UTF8' ))
{
    die('mysqli_set_charset() failed');
}

一旦你连接到数据库,不妨设置连接字符集。当你在你的应用程序中使用多种语言时,这绝对有必要。

否则会发生什么呢?你会在非英文文本中看到很多的方框和????????。

复制代码
代码如下:ob_start;采用输出缓存句柄的方法确实非常有效,而且不会给服务器带来什么特殊的负荷。但必须注意的是,Netscape
Communicator对压缩图形的支持不佳,因此除非你能够保证所有用户都使用IE浏览器,否则你应该禁止压缩JPEG和GIF图形。一般地,对于所有其他文件,这种压缩都有效,但建议你针对各种浏览器都分别进行测试,特别是当你使用了特殊的插件或者数据查看器时这一点尤其重要。注意事项:1、一些Web服务器的output_buffering默认是4069字符或者更大,即输出内容必须达到4069字符服务器才会flush刷新输出缓冲,为了确保flush有效,最好在ob_flush()函数前有以下语句:复制代码 代码如下:print str_repeat;
//以确保到达output_buffering值2、ob_*
系列函数是操作PHP本身的输出缓冲区,所以ob_flush只刷新PHP自身的缓冲区,而flush是刷新apache的缓冲区。所以,正确使用俩者的顺序是:先ob_flush,然后flush。ob_flush是把数据从PHP的缓冲中释放出来,flush是把缓冲内/外的数据全部发送到浏览器。3、不要误认为用了ob_start()后,脚本的echo/print等输出就永远不会显示在浏览器上了。因为PHP脚本运行结束后,会自动刷新缓冲区并输出内容。

10.使用带有正确字符集选项的htmlentities

PHP 5.4之前,使用的默认字符编码是ISO-8859-1,这不能显示例如À â
这样的字符。

$value = htmlentities($this->value , ENT_QUOTES , 'UTF-8');

从PHP
5.4起,默认编码成了UTF-8,这解决了大部分的问题,但你最好还是知道这件事,如果你的应用程序使用多种语言的话。

先介绍这10个技巧,剩下的PHP技巧我们将在接下来的文章中为大家分享,感谢您的阅读。

发表评论

电子邮件地址不会被公开。 必填项已用*标注