在 PHP 面试中,include、require、include_once、require_once 这 four 个语言结构几乎是必考题。看似简单,但真正能答全、答准的人并不多。本文将从行为差异、底层机制、使用场景和常见陷阱几个维度,帮你彻底搞懂这道经典面试题。
一、先给结论:四个结构的核心区别
| 结构 | 文件不存在时的行为 | 是否检查重复包含 | 执行时机 |
|---|---|---|---|
include |
发出 Warning,脚本继续执行 | 否 | 每次调用都包含 |
require |
发出 Fatal Error,脚本终止 | 否 | 每次调用都包含 |
include_once |
发出 Warning,脚本继续执行 | 是 | 仅首次包含 |
require_once |
发出 Fatal Error,脚本终止 | 是 | 仅首次包含 |
一句话总结:require 比 include 更严格,_once 后缀用于防止重复包含。
二、include 与 require 的本质区别
1. 错误处理级别不同
这是两者最核心的差异:
- include:当被包含文件不存在时,PHP 抛出
E_WARNING,脚本继续执行后续代码。 - require:当被包含文件不存在时,PHP 抛出
E_COMPILE_ERROR(致命错误),脚本立即终止。
// include 示例
include 'not_exist.php';
echo '这行代码会执行'; // 会输出
// require 示例
require 'not_exist.php';
echo '这行代码不会执行'; // 不会输出
2. 适用场景不同
- 用
include:被包含的文件是可选的,比如模板片段、广告位、统计代码。即使缺失也不应影响主流程。 - 用
require:被包含的文件是必需的,比如配置文件、数据库连接、核心函数库。缺失时程序无法正常运行,应该立即报错终止。
3. 一个常被忽略的细节
在 PHP 7 之前,include 失败返回 false,而 require 失败会直接终止。从 PHP 7 开始,两者在文件不存在时都会产生 Warning,但 require 仍会抛出致命错误并终止脚本。面试中如果被追问版本差异,这一点可以加分。
三、_once 后缀的作用与原理
include_once 和 require_once 在功能上分别等同于 include 和 require,但增加了一个判断:如果该文件已经被包含过,则不再重复包含。
1. 为什么需要 _once
在大型项目中,一个文件可能被多个文件间接引用。例如:
// a.php
require 'config.php';
// b.php
require 'config.php';
// index.php
require 'a.php';
require 'b.php'; // config.php 会被包含两次
如果 config.php 中定义了函数或类,第二次包含就会报“函数/类已定义”的致命错误。使用 require_once 可以避免这个问题。
2. 底层实现原理
PHP 内部维护了一个已包含文件列表(included_files),键是文件的绝对路径。每次调用 _once 结构时,PHP 会先检查该路径是否已在列表中,如果在则直接跳过。
注意:判断依据是解析后的真实路径,而不是你写的相对路径。这意味着 ./config.php 和 config.php 如果指向同一文件,_once 能正确识别为重复。
3. _once 的性能代价
_once 需要额外的路径解析和哈希查找,理论上比普通 include/require 稍慢。但在现代 PHP(7.x/8.x)中,这个开销几乎可以忽略。不要为了微小的性能提升而放弃 _once 带来的安全性。
四、四个结构的返回值
这一点经常被面试官追问:
- 包含成功且文件没有显式
return时,返回1(int)。 - 如果被包含文件中有
return语句,则返回该值。 - 包含失败时,
include返回false,require终止脚本。
// config.php
return ['host' => 'localhost'];
// index.php
$config = include 'config.php';
var_dump($config); // array(1) { ["host"]=> string(9) "localhost" }
这个特性常用于让配置文件返回数组,是现代 PHP 框架的常见做法。
五、常见面试陷阱
陷阱 1:include 和 require 是函数吗?
不是。 它们是语言结构(language construct),不是函数。因此可以这样写:
if ($condition) {
include 'file.php';
}
但你不能用 function_exists('include') 检测,也不能把它们当作回调传递。
陷阱 2:括号问题
include('file.php'); // 合法,但不是函数调用
include 'file.php'; // 推荐写法
虽然加括号也能运行,但本质上括号只是表达式的一部分,不代表函数调用。
陷阱 3:路径查找顺序
当使用相对路径时,PHP 会依次在 include_path 配置的目录和当前脚本目录中查找。这可能导致意外的文件被包含。生产环境建议使用绝对路径:
require_once __DIR__ . '/config.php';
陷阱 4:_once 不能替代良好的架构
有些开发者滥用 require_once,认为加了 _once 就万事大吉。实际上,过度依赖 _once 往往掩盖了依赖关系混乱的问题。现代项目更推荐使用 Composer 的 autoload 机制,从根源上避免手动包含。
六、面试答题模板
如果面试中被问到这道题,可以按以下结构回答:
- 先分类:
include/require是一组,include_once/require_once是另一组。 - 讲错误处理:include 警告后继续,require 致命错误终止。
- 讲 _once:检查已包含文件列表,防止重复包含导致的函数/类重定义。
- 讲场景:必需文件用 require,可选文件用 include;核心库用 _once 防重复。
- 补充细节:它们是语言结构而非函数,有返回值,判断依据是真实路径。
七、总结
| 你的需求 | 推荐使用 |
|---|---|
| 加载必需的配置文件、核心类库 | require_once |
| 加载必需但确定不会重复的文件 | require |
| 加载可选的模板、片段 | include_once 或 include |
| 现代项目 | Composer autoload + require_once 引导文件 |
掌握这四个结构的区别,不只是为了应付面试,更是写出健壮 PHP 代码的基础。记住一个原则:必需用 require,可选用 include,防重复加 _once,路径尽量用绝对。
未经允许不得转载:任鹏个人博客 » PHP 面试题:include、require、include_once、require_once 的区别

