请离开include

尽量使用include, 而不是include_once, 理由是 include_once需要查询一遍已加载的文件列表, 确认是否存在, 然后再加载
 

诚然, 这个理由是对的, 不过, 我今天要说的, 是另外一个的原因.
我们知道, PHP去判断一个文件是否被加载, 是需要得到这个文件的opened_path的, 意思是说, 比如:

复制代码 代码如下:

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

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

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

1. 尝试解析文件的绝对路径, 如果能解析成功, 则检查EG(included_files), 存在则返回, 不存在继续
2. 打开文件, 得到文件的打开路径(opened path)
3. 拿opened path去EG(included_files)查找, 是否存在, 如果存在则返回, 不存在继续
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实现的一直不好, 会有一些未定义的问题, 比如:

复制代码 代码如下:

    <?php
    set_include_path("/tmp");
    function a($arg = array()) {
        include_once("b.php");
    }

    a();
    a();
    ?>

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

复制代码 代码如下:

    <?php
      class B {}
    ?>

那么在打开apc.include_once_override的情况下, 连续访问就会得到如下错误:
Fatal error - include() : Cannot redeclare class

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

你使用include_once,只能证明, 你对自己的代码没信心.
所以, 建议大家, 不要再使用include_once

时间: 2024-11-08 22:21:58

请离开include的相关文章

请离开include_once和require_once_php技巧

诚然, 这个理由是对的, 不过, 我今天要说的, 是另外一个的原因.我们知道, PHP去判断一个文件是否被加载, 是需要得到这个文件的opened_path的, 意思是说, 比如: 复制代码 代码如下:     <?php    set_include_path("/tmp/:/tmp2/");    include_once("2.php");    ?> 当PHP看到include_once "2.php"的时候, 他并不知道这个

c++-最小向量乘积,遇见错误请指正

问题描述 最小向量乘积,遇见错误请指正 #include <algorithm>#include <cmath>#include <cstdio>#include <cstring>#include <iostream>#include <list>#include <map>#include <queue>#include <set>#include <string>#include

c语言-C语言字符串问题 请指教

问题描述 C语言字符串问题 请指教 #include void main() { char *p="47340"; printf("%sn",*p); } 这个哪里有问题?谢谢. 解决方案 *p 是取值 p是地址,字符串的首地址就是字符串本身 解决方案二: 请使用下面的语句输入字符串. printf("%sn",); 解决方案三: *p不是访问的指针所指的内容? 解决方案四: char *p="47340"; -> ch

c语言-C语言switch语句 错误 请指教

问题描述 C语言switch语句 错误 请指教 #include ""stdio.h""void main(){ int yearmonthday;//定义年月天数,闰年等于366天,平年等于365天 printf(""请输入月份.年份:""); scanf(""%d%d""&month&year); switch(month) { case 1:day=31;break

TASK_KILLABLE:Linux 中的新进程状态【转】

转自:https://www.ibm.com/developerworks/cn/linux/l-task-killable/index.html 新的睡眠状态允许 TASK_UNINTERRUPTIBLE 响应致命信号 Linux kernel 2.6.25 引入了一种新的进程状态,名为 TASK_KILLABLE,用于将进程置为睡眠状态,它可以替代有效但可能无法终止的 TASK_UNINTERRUPTIBLE 进程状态,以及易于唤醒但更加安全的 TASK_INTERRUPTIBLE 进程状态

八一八小米和魅族之间不为人知的恩恩怨怨

就现在的资料和两者的相似程度来说.这两人之间有以下几点: 1.同样都是高配低价做手机的思路 2.期货定价,在放风时候性价比无敌,并且通过拖延上市时间来达到成本控制. 3.用论坛炒作替代广告,而魅族炒作的时候还没有微薄.在小米出现后就有了更好的平台. 4.长期预订,集中放货,从而造成人为热销.魅族在发布M9前订货2个多月,并且把多个门店集中到一个地方拿货,使得造成了在1月1日上市的大排队.而小米后的互联网抢购基本上就是魅族方式的互联网翻版. 5.注重外观和UI,重视用户体验,其实都是学苹果的,魅族

IOS开发--常用工具类收集整理(Objective-C)(持续更新)

 前言:整理和收集了IOS项目开发常用的工具类,最后也给出了源码下载链接. 这些可复用的工具,一定会给你实际项目开发工作锦上添花,会给你带来大大的工作效率. 重复造轮子的事情,除却自我多练习编码之外,就不要傻傻的重复造轮子了,还是提高工作效率,早点完成工作早点回家陪老婆孩子. 所以下面备份的常用工具类一定是你需要的. 前提:你有一定的开发经验,知道它们在开发的什么地方需要,你都不知道用在哪里,那你需要个毛啊,还是好好另外学好基础吧.少儿不宜,请离开哦. 插件目录列表:(持续更新和添加) 1.UI

学习ASP文件引用的方法

#include命令用于在多重页面上创建需重复使用的函数.页眉.页脚或者其他元素等. #include 命令 通过使用#include命令,我们可以在服务器执行某个ASP文件之前,把另一个ASP文件插入这个文件中.#include命令用于在多重页面上创建需重复使用的函数.页眉.页脚或者其他元素等. 如何使用#include命令 这里有一个名为"mypage.asp"的文件: 以下为引用的内容: <html> <body> <h3>Words of W

ASP网页防SQL注入的代码

近日笔者的小站遭受到SQL入侵,于是上网搜索了一些相关防SQL注入的方法. 版本颇多,有人觉得这段好用,有人以为那段才行,因此综合整理了一下,包含以下几种: 以下为引用的内容:<% Dim Fy_Url,Fy_a,Fy_x,Fy_Cs(),Fy_Cl,Fy_Ts,Fy_Zx '---定义部份 头------ Fy_Cl = 1 '处理方式:1=提示信息,2=转向页面,3=先提示再转向 Fy_Zx = "index.Asp" '出错时转向的页面 '---定义部份 尾------ O