接手一个跑了六年的老项目,每个调用扩展函数的地方都套了一层判断,比如判断 mb_substr 存不存在,包了却没有 else 分支,扩展真缺失时照样报错。这种写法看着保险,实际没什么用。
它只回答一个问题
function_exists 接收一个函数名字符串,返回这个函数在当前环境里是否已被定义。它只能判断函数,判断类要用 class_exists,判断方法用 method_exists,判断常量用 defined,判断扩展用 extension_loaded。分不清这四个,就会写出永远返回真的无效判断。
典型使用场景
一份代码要在多个客户环境跑,对方服务器扩展装得不一样,用它先探一下有没有 imagecreate、curl_init 这类函数,没有就走降级路径。这个用途是成立的。另一个用途是判断主机是否禁用了危险函数,被禁用时它会返回 false。
正确的兼容写法
if (!function_exists(mb_substr)) { function mb_substr($str, $start, $len = null) { return substr($str, $start, $len); } }注意这里是在函数不存在时才定义同名的替代函数,不是简单包一层就完事。替代实现的行为往往和真扩展不一致,中文截断容易出乱码,能装扩展就别用替身糊。
别把它放进循环
每次调用都有一次哈希查找开销,几万次的循环里反复判断同一个函数纯属浪费。在文件顶部判断一次,结果存进常量或者静态变量,后面直接用。判断结果在整个请求周期内不会变,缓存起来完全安全。
排查扩展问题的更快路径
与其在代码里到处埋判断,不如上线前执行 php -m 打印已加载扩展清单,对着功能清单核一遍。缺什么装什么,比在业务代码里写一堆分支干净得多。真要做兼容,也集中在一个环境适配文件里处理,别散落到各个业务函数中。