请远离include_once和require_once

时间:2022-09-17 20:02:48

尽量使用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

请远离include_once和require_once的更多相关文章

  1. 请远离include&lowbar;once和require&lowbar;once&lbrack;转&rsqb;

    来自:http://www.poluoluo.com/jzxy/201306/216921.html 尽量使用include, 而不是include_once, 理由是 include_once需要查 ...

  2. 深入掌握include&lowbar;once与require&lowbar;once的区别

    转:http://www.jb51.net/article/38587.htm  http://www.360doc.com/content/12/1022/17/7851074_243107406. ...

  3. php 中使用include、require、include&lowbar;once、require&lowbar;once的区别

    在PHP中,我们经常会通过include.require.include_once.require_once来引用文件,都可以达到引用文件的目的,但他们之间又有哪些区别呢,接一下我们详细的介绍一下 i ...

  4. php-5&period;6&period;26源代码 - include&lowbar;once、require&lowbar;once、include、require、eval 的opcode处理器

    # ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER 实现在文件 php-\Zend\zend_vm_execute.h static int ZEND_FASTCALL ...

  5. include、require、include&lowbar;once和require&lowbar;once的区别

    /*** * 1.include 和 require 的文件可以有返回值 * 2.include 包含的文件不存在,会发出一个警告,但是不会停止执行代码. * require 在这种情况下会抛出错误并 ...

  6. PHP中include、require、include&lowbar;once、require&lowbar;once的区别

    include:使用include引用外部文件时,只有代码执行到include代码段时,调用的外部文件才会被引用并读取,当引用的文件发生错误时,系统只会给出个警告错误,而整个php文件会继续执行.re ...

  7. include&comma;include&lowbar;once&comma;require&comma;require&lowbar;once的区别

    1.include() include(/path/to/filename) include()语句将在其被调用的位置处包含一个文件.包含一个文件与在该语句所在位置复制制定文件的数据具有相同内容的效果 ...

  8. 【PHP】- include、require、include&lowbar;once 和 require&lowbar;once的区别

    1.include:会将指定的档案读入并且执行里面的程序.      被导入的档案中的程序代码都会被执行,而且这些程序在执行的时候会拥有和源文件中呼叫到 include() 函数的位置相同的变量范围( ...

  9. 初学 Java Web 开发,请远离各种框架,从 Servlet 开发

    Web框架是开发者在使用某种语言编写Web应用服务端时关于架构的最佳实践.很多Web框架是从实际的Web项目抽取出来的,仅和Web的请求和响应处 理有关,形成一个基础,在开发别的应用项目的时候则可以从 ...

随机推荐

  1. Node&plus;Socketio实现消息群发功能

    注:本博文是作者原创,转载请注明出处. 在项目中时常会使用到socketio,今天我们就来实现Node+socketio实现群发消息功能, 项目源码:https://github.com/zhangx ...

  2. deep learning 练习 多变量线性回归

    多变量线性回归(Multivariate Linear Regression) 作业来自链接:http://openclassroom.stanford.edu/MainFolder/Document ...

  3. 自己存档:table 的css

    border:0;margin:0;border-collapse:collapse;border-spacing:0;

  4. 我的c&plus;&plus;学习&lpar;4&rpar; C&plus;&plus;输入输出格式的控制

    默认进制:默认状态下,数据按十进制输入输出.如果要求按八进制或十六进制输入输出,在cin或cout中必须指明相应的数据形式,oct为八进制,hex为十六进制,dec为十进制. #include &qu ...

  5. pageX&sol;Y&comma; offset&lpar;&rpar;&comma; position&lpar;&rpar;&comma; scrollTop&lpar;&rpar;&comma; screenX&sol;Y&comma; clientX&sol;Y&comma; pageX&sol;Y

    event.pageX get mouse position Description: The mouse position relative to the left edge of the docu ...

  6. Input框去掉蓝色边框

    Input框去掉蓝色边框: <input type="text" name="" value="" class="Inpt& ...

  7. 一些static&lowbar;cast const&lowbar;cast

    static_cast:干杂活的,那三个都有各自的专有用途,那三个不做的都由这个转型符来做,只要它能做的,用C语法的强制类型转换运算符也一定能够完成:但话又说回来了,C强制类型转换能做的,它可不一定都 ...

  8. iOS开发关于AppStore程序的上传流程

    主要内容: 1.创建唯一标示符App ID(前提是你的程序在真机上测试没有任何问题) 2.申请发布证书 3.申请发布描述文件 4.iTunes Connect创建App并填写信息 5.选择证书编译打包 ...

  9. asp&period;net2&period;0安全性&lpar;1&rpar;--用户角色篇&lpar;类&rpar;--转载来自车老师

    Membership.MembershipUser和Roles类 用户与角色管理在asp.net2.0中是通过Membership和Roles两个类来实现的. Membership:用户成员账号管理, ...

  10. linux安装jdk以及tomcat

    一.卸载旧jdk 1.检测原OPENJDK版本 java -version 查看是否安装了jdk,并且是什么版本 2.进一步查看JDK信息 rpm -qa|grep java tzdata-java- ...