never 类型强制函数必须终止或抛出异常,PHP 8.1+ 中禁止 return 或自然结束,仅允许 throw 或 exit()/die();它不是 void,而是“后续代码绝不会执行”的确定性承诺,支持死代码检测与类型推导,但不可用于联合类型或重载。

never 类型强制函数必须终止或抛出异常
声明 never 的函数在 PHP 8.1+ 中被严格限制:它不能执行 return,也不能自然结束作用域。一旦违反,立即触发 Fatal error: A never-returning function must not return。
这和 void 有本质区别:void 允许函数正常执行完(比如只做日志、赋值),而 never 是一种“承诺”——调用它之后,后续代码**绝不会执行**。
- 合法方式只有两种:显式
throw异常,或调用exit()/die() - 哪怕只是漏写一个
throw,或者在if分支里忘了覆盖所有路径,PHP 就会在运行时中断 - 静态分析工具(如 PHPStan)能据此推断“此处之后的代码不可达”,自动标记死代码
never 让 IDE 和类型系统信任控制流
当你写 redirect(string $url): never,IDE 不再需要猜“这个函数会不会返回”。它知道调用后流程已终结,于是:
- 自动忽略该调用之后的语句(比如
do_something_else()会被标灰或报 unreachable code) - 在联合类型或泛型上下文中,
never作为“底部类型”,可安全参与类型推导(例如T|never等价于T) - 函数内联或重构时,工具能准确判断哪些变量/作用域已失效,避免误删或误保留
对比旧写法:function redirect(): void { header(...); exit(); } ——void 不提供任何流程保证,IDE 只能靠启发式猜测,容易出错。
立即学习“PHP免费学习笔记(深入)”;
never 不能用于联合类型或重载场景
never 是孤立类型,PHP 明确禁止它出现在联合类型中。下面这些写法都会报错:
-
function foo(): never|string→Fatal error: never can only be used as a standalone type -
function bar(): ?never→ 语法错误(never本身已隐含“不返回”,?冲突) - 继承父类方法并试图把返回类型从
void改为never?允许;但反过来(never→string)会破坏协变性,直接拒绝
这种限制不是 bug,而是设计使然:never 表达的是“无出口”的绝对语义,混入其他类型会消解它的确定性。
真实项目中最容易踩的坑
实际迁移时,开发者常在三类地方误用 never:
- 把“大概率抛异常”的函数标成
never,比如数据库查询封装——如果底层没真正throw或exit,只是返回false,就违反契约 - 在条件分支中只处理了部分情况,漏掉
else或默认分支,导致某些路径静默结束(PHP 会报错,但开发时可能没覆盖到所有分支) - 配合
#[ReturnTypeWillChange]混用——这个属性只适用于接口实现兼容过渡,不适用于never,加了也没用,反而掩盖问题
最稳妥的做法是:只对明确、无歧义的终止行为使用 never,比如 abort()、panic()、redirect() 这类框架级基础函数。业务逻辑层慎用。



















