PHP 面试题:include、require、include_once、require_once 的区别

在 PHP 面试中,includerequireinclude_oncerequire_once 这 four 个语言结构几乎是必考题。看似简单,但真正能答全、答准的人并不多。本文将从行为差异、底层机制、使用场景和常见陷阱几个维度,帮你彻底搞懂这道经典面试题。

一、先给结论:四个结构的核心区别

结构 文件不存在时的行为 是否检查重复包含 执行时机
include 发出 Warning,脚本继续执行 每次调用都包含
require 发出 Fatal Error,脚本终止 每次调用都包含
include_once 发出 Warning,脚本继续执行 仅首次包含
require_once 发出 Fatal Error,脚本终止 仅首次包含

一句话总结:requireinclude 更严格,_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_oncerequire_once 在功能上分别等同于 includerequire,但增加了一个判断:如果该文件已经被包含过,则不再重复包含

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.phpconfig.php 如果指向同一文件,_once 能正确识别为重复。

3. _once 的性能代价

_once 需要额外的路径解析和哈希查找,理论上比普通 include/require 稍慢。但在现代 PHP(7.x/8.x)中,这个开销几乎可以忽略。不要为了微小的性能提升而放弃 _once 带来的安全性。

四、四个结构的返回值

这一点经常被面试官追问:

  • 包含成功且文件没有显式 return 时,返回 1(int)。
  • 如果被包含文件中有 return 语句,则返回该值。
  • 包含失败时,include 返回 falserequire 终止脚本。
// 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 机制,从根源上避免手动包含。

六、面试答题模板

如果面试中被问到这道题,可以按以下结构回答:

  1. 先分类include/require 是一组,include_once/require_once 是另一组。
  2. 讲错误处理:include 警告后继续,require 致命错误终止。
  3. 讲 _once:检查已包含文件列表,防止重复包含导致的函数/类重定义。
  4. 讲场景:必需文件用 require,可选文件用 include;核心库用 _once 防重复。
  5. 补充细节:它们是语言结构而非函数,有返回值,判断依据是真实路径。

七、总结

你的需求 推荐使用
加载必需的配置文件、核心类库 require_once
加载必需但确定不会重复的文件 require
加载可选的模板、片段 include_onceinclude
现代项目 Composer autoload + require_once 引导文件

掌握这四个结构的区别,不只是为了应付面试,更是写出健壮 PHP 代码的基础。记住一个原则:必需用 require,可选用 include,防重复加 _once,路径尽量用绝对。

未经允许不得转载:任鹏个人博客 » PHP 面试题:include、require、include_once、require_once 的区别

赞 (0) 打赏

评论 0

取消
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏