
直接用 function_exists() 做前置判断最稳妥
PHP 报 Cannot redeclare function_name(),根本原因是同一请求周期里,同一个函数被 include 或 require 多次,而函数定义又没做保护。最直接、最兼容的解法就是定义前加一层检查——function_exists() 是 PHP 内置的轻量级运行时判断,开销几乎为零,且从 PHP 4 就存在,不用考虑版本兼容问题。
常见错误现象:在多个配置文件或工具类文件中都写了 function debug_log() { ... },然后通过 require_once 'utils.php' 加载,但某处误用了 require 'utils.php',或某个自动加载器重复引入了该文件。
- 必须把
function_exists()放在function关键字之前,不能包在条件块里再执行定义(否则可能触发解析错误) - 不要用
defined(),它只对常量有效,对函数无效 - 如果函数名来自变量(比如动态生成),
function_exists()仍可用,但需确保变量已赋值且不含非法字符
用 require_once 或 include_once 控制文件加载次数
函数重复定义,90% 源于文件被多次载入。虽然 require_once 看似“多此一举”,但它是在文件系统层面做去重,比函数级判断更早、更底层,能避免语法解析阶段就出错。
使用场景:公共函数库(如 helpers.php)、插件初始化脚本、框架的 functions.php 入口等需要被多处引用的文件。
立即学习“PHP免费学习笔记(深入)”;
-
require_once和include_once的判断依据是「文件绝对路径」,软链接、相对路径不同写法会被视为不同文件,务必统一路径规范 - 如果用 Composer 自动加载,就别再手动
require_once同一文件——PSR-4 加载器本身已保证单例,重复require_once反而可能干扰 autoloader 行为 - 注意 APCu 或 OPcache 开启时,
require_once的缓存行为不受影响,无需额外处理
改用 class + static 方法替代全局函数
长期维护的项目里,无命名空间的全局函数极易冲突。把函数收进类里,哪怕不实例化,也能靠类名隔离作用域,天然规避重名问题。
性能影响几乎可忽略:PHP 对 static 方法调用的优化很成熟,比函数调用略慢几个纳秒,业务代码里完全感知不到。
- 类名建议带业务前缀,比如
App_Helper::format_date(),比裸函数format_date()更易溯源 - 如果必须保留函数调用习惯,可用
function format_date() { return App_Helper::format_date(...); }做一层薄封装,但仅限兼容旧代码 - 避免在类里定义大量
public static方法却不加命名空间——这等于把全局函数换了个马甲
启用 declare(strict_types=1) 不解决重复定义,但能暴露隐性冲突
这个声明和函数重复定义无直接关系,但它会让类型声明更严格,间接帮你提前发现因文件重复加载导致的签名不一致问题。比如第一次定义 function foo(int $x),第二次不小心写成 function foo($x),strict mode 下会报 Declaration must be compatible,而不是静默覆盖或报错。
容易被忽略的地方:该声明必须放在文件**第一行非空白非注释行**,且只对当前文件生效;如果两个同名函数分别在 strict 和非 strict 文件里定义,PHP 仍会按顺序解析并报重复定义,不会因为 strict 模式跳过检查。
所以它不是解决方案,而是辅助排查的放大镜——尤其适合团队协作中多人修改同一函数库的场景。
真正要防重复定义,还是得靠 function_exists() + require_once 这套组合,别的都是锦上添花。边界情况往往出在 autoload 和手动 require 混用、测试环境反复 reload、CLI 脚本多次执行却没清理 opcode 缓存这些地方。











