「PHP」- include[_once] / require[_once]

  CREATED BY JENKINSBOT

内容:介绍include、include_once、require、require_once;

我就想知道:能不能把某个文件夹下的类一次性全部引入。

存在的问题

容易引发的一个问题就是引入了大量无用的类。

提前搜索了一下,看了德问社区的一个类似问题:http://www.dewen.net.cn/q/9824

我的另外一篇文章《PHP 自动加载类》,介绍了如何解决这个问题。本文的内容不是介绍类加载的。

言归正传

起初我并不想写,可以搜索到很多,但是不写的话,印象不深刻,所以还是要整理一下。
下面是关于 include、include_once、require、require_once

include

http://php.net/manual/zh/function.include.php

对引入文件的查找

被包含文件先按参数给出的路径寻找;
如果没有给出目录(参数只提供了文件名)时则按照 include_path 指定的目录寻找。
如果在 include_path 下没找到该文件,则 include 最后才在调用脚本文件所在的目录和当前工作目录下寻找。
如果最后仍未找到文件,则 include 会发出一条警告(E_WARNING),。

如果定义了路径(即参数中含有路径信息)include_path 都会被完全忽略。例如一个文件以 ../ 开头。

返回值

在失败时, include 返回 FALSE 并且发出警告。
在成功时,则返回 1。如果在被包含的文件中另外给出了返回值,则文件中的返回值为 include 的返回值。比如:

// demo.php
<?php

$value = 1234;
return $value;

?>

// test.php
<?php

$a = include 'demo.php';
echo $a; // 1234;

对引入文件的处理及变量、函数、类的作用域

当一个文件被包含时,其中所包含的代码继承了 include 所在行的变量范围。从该处开始,调用文件在该行处可用的任何变量在被调用的文件中也都可用。不过所有在包含文件中定义的函数和类都具有全局作用域。

如果 include 出现于一个函数里,则被调用的文件中所包含的所有代码将表现得如同它们是在该函数内部定义的一样。所以它将遵循该函数的变量范围。此规则的一个例外是魔术常量,它们是在发生包含之前就已被解析器处理的。

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

如果“URL fopen wrappers”在 PHP 中被激活(默认配置),可以用 URL(通过 HTTP 或者其它支持的封装协议——见支持的协议和封装协议)而不是本地文件来指定要被包含的文件。如果目标服务器将目标文件作为 PHP 代码解释,则可以用适用于 HTTP GET 的 URL 请求字符串来向被包括的文件传递变量。严格的说这和包含一个文件并继承父文件的变量空间并不是一回事;该脚本文件实际上已经在远程服务器上运行了,而本地脚本则包括了其结果。

因为 include 是一个特殊的语言结构,其参数不需要括号。在比较其返回值时要注意。

如果在包含文件中定义有函数,这些函数不管是在 return 之前还是之后定义的,都可以独立在主文件中使用。如果文件被包含两次,PHP 5 发出致命错误因为函数已经被定义,但是 PHP 4 不会对在 return 之后定义的函数报错。推荐使用 include_once 而不是检查文件是否已包含并在包含文件中有条件返回。

include_once

http://php.net/manual/zh/function.include-once.php

此行为和 include 语句类似,唯一区别是如果该文件中已经被包含过,则不会再次包含;

require

http://php.net/manual/zh/function.require.php

require 在出错时产生 E_COMPILE_ERROR 级别的错误,脚本终止运行。
include 只产生警告,脚本会继续运行。文档也没有过多的解释,只是说:参见 include 文档了解详情;

目前已知的正确的 include 和 require 的区别就是文件无法引入时的错误级别。

require_once

http://php.net/manual/zh/function.require-once.php

require_once 语句和 require 语句完全相同,唯一区别是 PHP 会检查该文件是否已经被包含过,如果是则不会再次包含。

总结

使用的话,如上所述,主要明白 include 的使用就可以了,剩下的类比就可以了;

“ require相当于预处理”,关于这个说法,我不知道下面的例子能不能证明这个说法是错误的:

<?php

// PHP7,可能您的PHP版本是其他的,但我真的想问:您验证过么?还是文档上有写;
// 我对他说的预处理的理解:程序执行之前,require 的文件就会被引入;

for($i = 0; $i < 5; $i++){
    $content  = "<?php echo $i;";
    file_put_contents(ROOT_PATH . '/tmp/_1.php', $content);
    require ROOT_PATH . '/tmp/_1.php';
}

// require 输出 01234
// include 输出 01234
// 如果真的是预处理,那输出是不会有变化的;

“include()是有条件包含函数,而 require()则是无条件包含函数”,关于这个说法,我不知道下面的例子能不能证明这个说法是错误的:

<?php

// PHP7,可能您的PHP版本是其他的,但我真的想问:您验证过么?还是文档上有写;

$start = memory_get_usage();

if(false){
    require ROOT_PATH . '/tmp/_1.php';
}

$end =  memory_get_usage();

echo $end - $start;

// 不管使用 include 或者 require, 内存的变化量都为 0;

既然文档没说,就不要去意淫一些有或者没有的东西。文档里说的东西不够你用的么?就算你说的是对的,人家都没说有这些特性,明摆着就是不让你用。。。

还有那些说 require 没有返回值的,很可能你的PHP版本是旧的,及其的旧:

<?php

// PHP7,可能您的PHP版本是其他的,但我真的想问:您验证过么?还是文档上有写;

$dimp = (require ROOT_PATH . '/tmp/_1.php');
var_dump($dimp);exit;

// 返回 int(1);