注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

@fc_lamp

关注Web应用解决方案MySql/PHP/Python一盏名为"飞川"的灯~

 
 
 

日志

 
 

关于PHP include(require)与include_once(require_once)  

2012-09-12 18:05:50|  分类: Web技术-Php |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
include与require的区别
  我们知道include与require除了在处理引入文件发错时不同方式外,其它完一样。include在引入不存文件时产生一个警告且脚本还会继续执行,而require 则导致一个致命性错误,脚本停止执行。因此下文所提到的include与include_once的区别包含了require与require_once。

2 include与include_once的区别
 
   The include_once 语句在脚本执行期间包含并运行指定文件。此行为和 include 语句类似,唯一区别是如果该文件中的代码已经被包含了,则不会再次包含。如同此语句名字暗示的那样,只会包含一次(也就是说:include_once需要查询一遍已加载的文件列表, 确认是否存在, 然后再加载)。

3 关于引入文件路径问题
 
   这个问题是一个比较头疼的问题,我们经常会因为采用不正确的引入文件方式而报:
Warning: include(./xx.php) [function.include]: failed to open stream: No such file or directory in D:\xxx\xxx\xxx.php on line 2
这与php.ini配置文件中的include_path有一定关系。
比如我有如下的目录结构(windows平台):
+root
      -ssoa
            -ssoa_index.php
    -ssoa_test.php
      -ssob
             -ssob_index.php
             -ssob_test.php

 ssoa_index.php文件里语句为:

<?php
include 'ssoa_test.php';
$ssoa_index = 'ssoa_index';

 ssoa_test.php 文件里语句为:

<?php
$ssoa_test = 'ssoa_test';

 那么当我们在ssob_test.php文件引入 ssoa_index.php文件并且要使用$ssoa_test变量时。
 如果我们不改变原include_path的默认配置(一般include_path都为"."值,即指向的是当前的工作目录 /ssob/):
我们可以这样做:
eg1

<?php
include '../ssoa/ssoa_index.php';
$ssob_test = 'ssob test';
var_dump($ssoa_test);
#输出:string 'ssoa_test' (length=9)

如果我们更改include_path默认值:
eg2

<?php
ini_set('include_path','../ssoa;ssob');
include 'ssoa_index.php';
$ssob_test = 'ssob test';
var_dump($ssoa_test);
#输出:string 'ssoa_test' (length=9)


不过,一般情况下我们PHPER很少去操作此值,并且常会写下如下代码:
ssoa_index.php文件里语句改为
eg3

<?php
include './ssoa_test.php';
$ssoa_index = 'ssoa_index';

ssob_test.php代码为:

<?php
include '../ssoa/ssoa_index.php';
$ssob_test = 'ssob test';
var_dump($ssoa_test);

再次运行脚本时,就会报错Warning: include(./ssoa_test.php) [function.include]: failed to open stream..................
这个与寻找包含文件的顺序有关
1) 如果要包含文件的路径是绝对的,那么按:在当前工作目录的相对的 include_path 下寻找,然后是当前运行脚本所在目录相对的 include_path 下寻找。比如在eg2中,我们最后直接 include 'ssoa_test.php'; 时则寻找 ssoa_test.php 的顺序上先在当前工作目录("/ssob/")的相对目录include_path("../ssoa") ,然后是 /root/ssoa/下寻找。

2)如果要包含的文件路径是相对的,那么只会在在当前工作目录相对的 include_path 下寻找。比如eg3中,include '../ssoa/ssoa_index.php';是能够包含文件ssoa_index.php的,因为它是从当前工作目录的上一级../(root)开始朝下找的即:"root/ssoa/",但是include './ssoa_test.php';时,./表示在当前工作目录(ssob)中寻找,所以找不到ssoa_test.php文件。

实际上,PHP 的 include() 包含语句在相对路径的问题处理的不是很好,很多时候使用相对路径引入文件时都会出错。引用别人的话说“别的编程语言在处理include中的相对目录时,都是以当前处理的文件作为基准。也就是说,如果A包含B,B包含C时,C再包含一个含相对路径的文件,那么路径是相对于C的。这样的处理很自然,符合人们的直觉,也便于开发出路径无关的程序包。可是PHP不这样,它优先相对工作目录来处理,并且如果路径中包含./ ../的话,则只相对于工作目录(可用getcwd()来获取当前的工作目录)。也许PHP这样处理有它的理由。”


4 include与include_once的抉择问题
  这里我转鸟哥的文章,参考:

作者:Laruence

源文:http://www.laruence.com/2012/09/12/2765.html/comment-page-1#comment-8441

再一次, 不要使用(include/require)_once


最近关于apc.include_once_override的去留, 我们做了几次讨论, 这个APC的配置项一直一来就没有被很好的实现过.

在这里, 我想和大家在此分享下, 这个问题的原因, 以及对我们的一些启示.

关于使用include还是include_once(以下,都包含require_once), 这个讨论很长了, 结论也一直有, 就是尽量使用include, 而不是include_once, 以前最多的理由的是, include_once需要查询一遍已加载的文件列表, 确认是否存在, 然后再加载.

诚然, 这个理由是对的, 不过, 我今天要说的, 是另外一个的原因.

我们知道, PHP去判断一个文件是否被加载, 是需要得到这个文件的opened_path的, 意思是说, 比如:

  1. <?php
  2. set_include_path("/tmp/:/tmp2/");
  3. include_once("2.php");
  4. ?>

当PHP看到include_once “2.php”的时候, 他并不知道这个文件的实际路径是什么, 也就无法从已加载的文件列表去判断是否已经加载, 所以在include_once的实现中, 会首先尝试解析这个文件的真实路径(对于普通文件这个解析仅仅类似是检查getcwd和文件路径, 所以如果是相对路径, 一般是不会成功), 如果解析成功, 则查找EG(include_files), 如果存在则说明包含过了, 返回, 否则open这个文件, 从而得到这个文件的opened_path. 比如上面的例子, 这个文件存在于 “/tmp2/2.php”.

然后, 得到了这个opened_path以后, PHP去已加载的文件列表去查找, 是否已经包含, 如果没有包含, 那么就直接compile, 不再需要open file了.

  1. 1. 尝试解析文件的绝对路径, 如果能解析成功, 则检查EG(included_files), 存在则返回, 不存在继续
  2. 2. 打开文件, 得到文件的打开路径(opened path)
  3. 3. 拿opened path去EG(included_files)查找, 是否存在, 如果存在则返回, 不存在继续
  4. 4. 编译文件(compile_file)

这个在大多数情况下, 不是问题, 然而问题出在当你使用APC的时候…

在使用APC的时候, APC劫持了compile_file这个编译文件的指针, 从而直接从cache中得到编译结果, 避免了对实际文件的open, 避免了对open的system call.

然而, 当你在代码中使用include_once的时候, 在compile_file之前, PHP已经尝试去open file了, 然后才进入被APC劫持的compile file中, 这样一来, 就会产生一次额外的open操作. 而APC正是为了解决这个问题, 引入了include_once_override, 在include_once_override开启的情况下, APC会劫持PHP的ZEND_INCLUDE_OR_EVAL opcode handler, 通过stat来确定文件的绝对路径, 然后如果发现没有被加载, 就改写opcode为include, 做一个tricky解决方案.

但是, 很可惜, 如我所说, APC的include_once_override实现的一直不好, 会有一些未定义的问题, 比如:

  1. <?php
  2. set_include_path("/tmp");
  3. function a($arg = array()) {
  4.     include_once("b.php");
  5. }
  6.  
  7. a();
  8. a();
  9. ?>

然后, 我们的b.php放置在”/tmp/b.php”, 内容如下:

  1. <?php
  2.   class B {}
  3. ?>

那么在打开apc.include_once_override的情况下, 连续访问就会得到如下错误:

  1. Fatal error - include() : Cannot redeclare class b

排除这些技术因素, 我也一直认为, 我们应该使用include, 而不是include_once, 因为我们完全能做到自己规划, 一个文件只被加载一次. 还可以借助自动加载, 来做到这一点.

你使用include_once, 只能证明, 你对自己的代码没信心.

所以, 建议大家, 不要再使用include_once。

  

另外重要一点:

当一个文件被包含时,语法解析器在目标文件的开头脱离 PHP 模式并进入 HTML 模式,到文件结尾处恢复。由于此原因,目标文件中应被当作 PHP 代码执行的任何代码都必须被包括在有效的 PHP 起始和结束标记之中。 否会被当成普通文件原样输出。


参考:http://cn.php.net/manual/zh/function.include.php


关于PHP include(require)与include_once(require_once) - fc_lamp - @fc_lamp

  评论这张
 
阅读(825)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017