
require 会中断脚本,include 只发警告
这是最直接的后果差异:当目标文件不存在或语法错误时,require 触发 Fatal error,整个 PHP 进程立刻终止;而 include 报 Warning,后续代码照常执行。
典型场景比如加载配置文件:require 'config.php' 更安全——如果连数据库连接参数都读不到,后面逻辑根本没意义;但加载一个可选的统计埋点脚本,用 include 'tracker.php' 更合理,挂了也不影响主流程。
- 错误信息示例:
Fatal error: require(): Failed opening required 'missing.php'(require) vsWarning: include(missing.php): failed to open stream(include) -
require_once和include_once也遵循同样中断/警告逻辑,只是多了一层“是否已加载过”的判断 - 别指望靠
@include完全吞掉错误——它只压制 warning,但若文件里有 parse error(如语法错),依然会报 fatal,且无法被 @ 捕获
require 和 include 都不是函数,是语言结构
它们没有返回值(严格说,include 有,require 没有),也不能像函数那样被变量赋值或传参调用。写成 $f = include 'a.php' 是合法的(include 返回文件最后一行表达式的值),但 $f = require 'a.php' 会直接报错。
常见误用是套括号:require('file.php') 看起来像函数调用,其实括号只是分组作用,和 require 'file.php' 完全等价。PHP 解析器根本不把它当函数看。
立即学习“PHP免费学习笔记(深入)”;
- 不能用在条件表达式右侧做“短路”判断:
if (include 'auth.php') { ... }可能执行,但语义混乱,不推荐 - 路径解析行为一致:都基于当前执行文件的位置(
__DIR__),不是包含文件自身的位置 - 它们都不受
auto_prepend_file或auto_append_file影响——这些 ini 设置只对主入口文件生效
include_once / require_once 的“已加载”判定很粗糙
PHP 判定“是否已包含过”,只比对传入的字符串路径(经过 realpath 展开后),而不是文件内容或 inode。这意味着:
- 同一文件用相对路径和绝对路径各引一次,会被算作两次——
require_once 'config.php'和require_once __DIR__ . '/config.php'会重复加载 - 软链接指向同一文件,但路径不同,也会被当成两个文件处理
- 不会检测文件是否被修改过,改了内容也不会重新加载(适合部署后静态环境,不适合开发中热更)
所以线上环境用 _once 版本防重复包含没问题;但开发时如果依赖自动重载,得关掉 opcode 缓存(opcache.enable=0)或手动 clear OPCache,否则改了文件也看不到效果。
性能差异几乎可以忽略,但路径写法影响真实开销
单纯比较 require 和 include 的执行速度,差几个纳秒,毫无实际意义。真正拖慢的是路径解析过程:每次调用都要做文件系统查找、权限检查、realpath 展开。
如果你写成 include '../lib/utils.php',PHP 就得从当前目录一层层往上找;而用 include __DIR__ . '/../lib/utils.php',路径是确定的字符串拼接,跳过大量 fs 操作。
- 所有包含语句最好都用
__DIR__或dirname(__FILE__)开头,避免相对路径歧义 - 不要在循环里动态拼路径并
include——每次都会触发完整文件查找,哪怕内容一样 - OPcache 启用后,
require/include的字节码会被缓存,但首次加载仍要走磁盘;_once版本在 opcache 中也有额外哈希表查询开销,不过仍是微乎其微
路径写得随意,比选 require 还是 include 对性能的影响大得多。











