php 5.5及更早版本需手写阶乘函数,推荐用for循环从2开始累乘,严格校验输入类型与范围,避免溢出、内存耗尽及无声计算失真。

PHP 5.5 及更早版本没有 gmp_fact(),bcfact() 也不存在,连 array_product(range(1, $n)) 都可能在 $n 较大时因整数溢出或内存报错而失效——这时候得靠手写循环或递归,但必须避开常见陷阱。
用 for 循环手动累乘(最稳)
这是兼容性最强、可控性最高的方式,适用于 PHP 4+ 所有版本,且能提前判断边界、避免负数或非整数输入导致逻辑错误。
- 必须先用
is_int()或ctype_digit()+(int)强转校验输入,0和1要直接返回1 - 别用
range(1, $n)再array_product():PHP 5.2 下range()对大数会耗尽内存,且array_product()在溢出时返回0而非报错,结果不可信 - 循环变量建议从
2开始,跳过1的乘法,减少一次迭代
function factorial($n) { if (!is_int($n) || $n < 0) return false; if ($n === 0 || $n === 1) return 1; $result = 1; for ($i = 2; $i <= $n; $i++) { $result *= $i; } return $result; }
需要支持大数?用 bcmath 模拟(PHP 4.0.4+)
当 $n > 20 就超出 int 范围(32 位系统下最大约 2^31−1),此时原生整数会静默溢出。用 bcmul() 可绕过限制,但前提是服务器启用了 bcmath 扩展(默认不总开启)。
-
bcadd()、bcmul()等函数所有参数必须是字符串,(String)$n不够安全,要用number_format($n, 0, '.', '')或正则清理小数点 - 初始值不能写
bcadd('0', '1'),直接用'1'字符串即可;每次乘法后记得用trim()去首尾空格,避免后续计算失败 - 性能比原生整数慢 10–50 倍,$n > 1000 时明显卡顿,慎用于高频调用场景
function bcfactorial($n) { if (!is_int($n) || $n < 0) return false; $n = (string)$n; $result = '1'; for ($i = 2; $i <= $n; $i++) { $result = bcmul($result, (string)$i); } return $result; }
递归写法?PHP 5.2 默认栈深度仅 100,慎用
看似简洁,但 PHP 旧版默认 xdebug.max_nesting_level=100,且递归无尾调用优化,$n > 90 就大概率触发 Fatal Error: Maximum function nesting level of '100' reached。
立即学习“PHP免费学习笔记(深入)”;
- 即使调高配置,递归仍比循环多出函数调用开销,PHP 5.3 前不支持闭包绑定,无法优雅缓存中间结果
- 若坚持用递归,务必加深度防护:
if ($n > 80) return false;,而不是依赖 try/catch 捕获致命错误(PHP 中 fatal error 无法被try/catch捕获) - 别写
return $n * factorial($n-1)这种裸递归:没做类型检查,$n 是浮点数时会无限递归直到崩溃
真正麻烦的不是写不出阶乘,而是旧版 PHP 下整数溢出不报错、大数计算无声失真、扩展依赖不明确——这些细节在调试时才暴露,但线上环境往往只给你一个错得离谱的结果。