require_once 通过维护已加载文件的绝对路径列表防止重复包含,仅在同一请求生命周期内有效,不检查文件内容;与 include_once 仅错误级别不同,前者遇错终止,后者警告继续;重复声明函数等错误需自行加存在性检查。

require_once 为什么能防止重复包含
它在 PHP 运行时维护一个已加载文件的内部列表,每次执行 require_once 前先查这个列表;如果路径(注意:是解析后的绝对路径)已存在,就直接跳过,不报错也不再执行。不是靠文件名字符串匹配,所以 require_once 'foo.php' 和 require_once './foo.php' 在同一脚本中可能被当成两个不同文件——这是最常踩的坑。
- 实际判断依据是
realpath()后的路径,软链接、相对路径、符号路径都可能触发重复加载 - 它只对「同一个请求生命周期」有效;FPM 模式下每次 HTTP 请求都是独立的,不能跨请求去重
- 不会检查文件内容是否相同,只看路径是否已被
require_once或include_once加载过
require_once 和 include_once 的关键区别在哪
只有错误级别不同:require_once 遇到文件不存在或语法错误会抛出 Fatal error 并终止脚本;include_once 则抛出 Warning,脚本继续执行。其他行为完全一致——路径去重逻辑、解析方式、返回值(成功时返回 1)全一样。
- 用
require_once更适合加载关键类文件、配置、函数库——缺了就该挂,不该硬撑 -
include_once适合可选模板、语言包等容错场景,但实际项目中极少这么用 - 别混用:同一文件既
require_once又include_once,后者仍会被跳过(因为路径已登记)
为什么有时 require_once 还是报“Cannot redeclare function”
因为 require_once 只管文件是否加载过,不管里面定义的内容是否已存在。如果 A.php 里定义了 function foo(),而 B.php 也定义了同名函数,且两者都被 require_once 引入(比如通过不同入口),就会在第二次定义时爆错。
- 典型场景:多个插件各自
require_once 'helpers.php',但没做函数存在性检查 - 解决办法不是换
include_once,而是加保护:用if (!function_exists('foo')) { function foo() { ... } } - 类定义不受影响(PHP 本身禁止重复
class声明),但 trait 和 interface 同样会触发重复声明错误
性能和自动加载器的关系
现代 PHP 项目基本不用 require_once 手动加载类,而是靠 Composer 的自动加载机制。此时 require_once 主要用于加载非类文件:配置数组、全局常量、一次性初始化脚本等。
立即学习“PHP免费学习笔记(深入)”;
- Composer 自动生成的
vendor/autoload.php本身是用require_once加载的,但它内部用的是spl_autoload_register(),和require_once的去重无关 - 不要在自动加载回调里再写
require_once—— 自动加载器本职就是确保每个类只加载一次,自己再套一层反而容易绕过逻辑 - CLI 脚本里如果反复
require_once同一配置文件,要注意变量作用域:它只在首次执行时生效,后续 require 不会重跑代码,但也不会重置已有变量
路径解析和函数/类声明的边界,才是最容易被忽略的复杂点。写的时候觉得“反正只 include 一次”,结果运行时发现路径算错了,或者忘了函数得自己防重声明。











