PHP中重复定义同名函数会触发致命错误,因解析器在编译期注册函数名;需用function_exists()防护,避免require_once误判路径不同而重复加载。

include 两次同名函数就报错
PHP 解析器在运行时遇到 function foo() {} 这类定义,会立即注册该函数名到当前作用域。如果同一作用域内第二次见到同名定义(哪怕逻辑上在不同 include 文件里),就会抛出 Fatal error: Cannot redeclare foo()——这不是警告,是直接中断执行的致命错误。
常见触发场景:
- 主文件中写了
include 'funcs.php'; include 'funcs.php'; - 两个不同路径的
include实际指向同一个文件(如./inc/common.php和../includes/common.php) - 某个被包含的文件内部又包含了另一个含同名函数的文件,形成隐式重复加载
require_once 也不保险?
require_once 只保证「同一文件路径」不被重复加载,但对「同名函数」无感知。它防不住以下情况:
- 两个文件内容完全一样、函数名也一样,但路径不同(
lib/utils.php和vendor/mylib/utils.php)→require_once会分别加载,照样重声明 - 自动加载器(
spl_autoload_register)和手动require_once混用,导致同一函数被不同机制加载两次 - 子主题中覆盖父主题文件时,父主题的
functions.php已加载过某函数,子主题又通过get_template_part或直接include再次引入
怎么安全地加函数(尤其兼容旧 PHP)
如果你必须提供一个可能与内置函数同名的函数(比如 array_column),不能靠运气赌加载顺序,得主动防御:
立即学习“PHP免费学习笔记(深入)”;
- 用
function_exists('array_column')包裹自定义定义,只在缺失时才声明 - 不要在循环体或条件分支里写
function定义——PHP 不允许“运行时声明”,哪怕只执行一次 - 避免用极短、通用名(如
go()、dump()),这类名字极易和框架、扩展冲突(PHPCMS 的go()就和 Swoole 冲突) - 函数定义一律放在文件顶部,调用放在下面;别把
function GetValue($x) { }放在while循环之后——PHP 要求“先声明,后调用”,否则可能因执行顺序问题漏掉解析
类和函数的处理逻辑其实一致
PHP 对 class 和 function 的重复声明限制是同一套机制:编译期注册,不可覆盖。所以 class_exists('Foo') 和 function_exists('foo') 是对称的防护手段。但要注意:class_exists('Foo', false) 的第二个参数设为 false,可跳过自动加载,避免因加载失败引发额外错误——这点常被忽略。
真正难排查的,往往是跨文件、跨加载机制、路径归一化失败带来的“看似不同实则相同”的重复;与其事后 debug,不如从第一行 function 开始,就用 function_exists 套住。



















