再一次, 不要使用(include/require)_once
最近关于apc.include_once_override的去留, 我们做了几次讨论, 这个APC的配置项一直一来就没有被很好的实现过.
在这里, 我想和大家在此分享下, 这个问题的原因, 以及对我们的一些启示.
关于使用include还是include_once(以下,都包含require_once), 这个讨论很长了, 结论也一直有, 就是尽量使用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 b
(后记 2012-09-15 02:07:20: 这个APC的bug我已经修复: #63070)
排除这些技术因素, 我也一直认为, 我们应该使用include, 而不是include_once, 因为我们完全能做到自己规划, 一个文件只被加载一次. 还可以借助自动加载, 来做到这一点.
你使用include_once, 只能证明, 你对自己的代码没信心.
所以, 建议大家, 不要再使用include_once
再一次, 不要使用(include/require)_once的更多相关文章
- include require include_once require_once
include 使用方法: include "test.php"; 一般是放在流程控制的处理部分中使用,将文件内容引入.PHP程序在遇到include语句时,才将它读进来,这种方式 ...
- php学习笔记6--php中的文件包含 include,require,include_once,require_once
php中的文件包含 include,require,include_once,require_once 文件包含:是指将一个文件的内容包含进另外一个文件,有利于代码的复用等.php中文件包含指令有4个 ...
- php include,require,include_once,require_once 的区别
include(),require(),include_once(),require_once()作用都是包含并运行指定文件,但是使用场景又有很大区别. 1.include()和require()的区 ...
- PHP 文件包含总结 include require 命名空间 autoload spl_autoload_register 读取文件路径
总结: 1. include或require包含其他文件 使用./或者 ../,这里的当前路径和上一层路径,取决于运行脚本的路径,会存在如下问题. 在写PHP程序时,经常要用到include或requ ...
- [前端引用] 利用ajax实现类似php include require 等命令的功能
利用ajax实现类似php中的include.require等命令的功能 最新文件下载: https://github.com/myfancy/ajaxInclude 建议去这里阅读readme-2. ...
- php include require
includ和require都是把其他页面加载当前页面,不过不同的是,require如果没有找到,或者所包含的页面里面有错误就不会往下执行了 <?php include 'form.php'; ...
- php包含(include/require)文件时的作用域
当一个php脚本被require/include时,他的变量作用域根据其上下文环境决定. 1.如果是在一个函数中require/include一个文件,则此文件中的变量作用域是这个函数的范围.也就是说 ...
- PHP内的包含语句(include(),require(),include_once(),require_once())
背景:继续总结PHP内的函数. 在一般的程序中,我们经常重复用到一些代码,但是如果只是简单的进行代码复制,则会增加代码的冗余度,不便于程序的运行.因此,我们可以把重复性的代码分离出来,以外部文件的方式 ...
- PHP 站点相对包含,路径的问题解决方法(include,require)
以前看了,很多框架,基本上很少使用相对路径包含.而一般很多做php web站点,喜欢用相对路径. 认为这样,无论目录放到那里. 只要跟另外目录关系一致.那么就不会出现问题.如果一个站点,一般都认为,如 ...
随机推荐
- Python Django的生产部署方式
本地化部署的Django有很大的局限性,无法用于生产环境,比如无法抗住多并发,无法长时间的运行,容易造成网页无响应的问题.所以如何将Django部署到真正的生产环境中,让其能够真正的像正常的网页一样工 ...
- SAPUI5 freestyle vs SAP Fiori Elements —— 两种开发SAP UI5 Apps的方式对比
概述 目前SAPUI5 SDK 提供了两种方式来开发一个SAPUI5 App.一种方式是传统的SAPUI5开发方式,一种是利用SAP Fiori Elements通过模板快速构建应用的方式. 本文简单 ...
- SQL Server将自己的查询结果作为待查询数据子列之一
嵌套子查询是SQL语句中比较常用的一种查询方法,开发过程中遇到查询需要将自己的某列作为待查询的数据,在参考别人的SQL语句的写法终于实现了自己需要的功能. 查询语句如下: SELECT DISTINC ...
- EntityFramework Core 1.1+ Backing Fields(返回字段)
前言 通过我发表的博文可知最近一段时间会将持续讲解EntityFramework Core特性,在此之前我提到过Backing Fields,回头翻了翻感觉写的还不够好,于是乎再来讲解一番,也是自己再 ...
- Problem : 1002 ( A + B Problem II )
经验总结:一定要注意输出的格式,字符的空格,空行,一定要观察清楚.如本题的最后一个输出结果后面没有空行.最后代码实现的时候需要判断一下,代码如下 !=n) cout<<endl; Prob ...
- EOS 开发进展速报
Daniel Larimer 刚刚披露了 EOS 的最近开发进展,原文 :https://steemit.com/eos/@dan/ukoxz-eos-io-development-update 为了 ...
- ListIterator
1,ListIterator与Iterator Iterator的功能:next(),hasNext(),remove() 功能太少,因此出现了ListIterator,他的功能要比Iterator多 ...
- 如何通过TortoiseGit(小乌龟)把本地项目上传到github上
1.第一步: 安装git for windows(链接:https://gitforwindows.org/)一路next就好了, 如果遇到什么问题可以参考我另外一篇文章~^ - ^ 2.第二步:安装 ...
- 详解Tomcat线程池原理及参数释义
omcat线程池有如下参数: maxThreads, 最大线程数,tomcat能创建来处理请求的最大线程数 maxSpareTHreads, 最大空闲线程数,在最大空闲时间内活跃过,但现在处于空闲,若 ...
- 搭建hadoop伪分布式环境
伪分布式就是只有一台机器,既是namenode又是datanode.一台阿里云服务器(centos)即可完成. Java环境 首先需要安装Java环境,下载jdk的安装包,解压到/usr/java/, ...