PHP递归算阶乘易爆内存,因默认栈深度有限,factorial(1000)会触发内存耗尽或嵌套层级超限;应改用迭代实现,避免递归风险。

PHP递归算阶乘直接爆内存?别用递归
PHP默认栈深度有限,factorial(1000) 这种递归写法会快速触发“Allowed memory size exhausted”或“Maximum function nesting level reached”。这不是内存配得不够,是递归本身在PHP里就是高危操作。
改用迭代是最直接的解法:
function factorial($n) {
if ($n < 0) return false;
$result = 1;
for ($i = 2; $i <= $n; $i++) {
$result *= $i;
}
return $result;
}
- 避免函数调用栈累积,内存占用恒定(O(1))
- 支持到
$n ≈ 10^5都没问题(瓶颈转为整数溢出或字符串精度) - 若需超大数(如
factorial(10000)),必须用bcmul+ 字符串模拟,不能依赖原生int
php.ini里开大memory_limit没用?因为不是内存问题
看到“memory exhausted”就去改 memory_limit 是常见误区。递归爆的是**栈空间**,不是堆内存;memory_limit 管的是堆,对栈深度完全无效。
真正相关的是:
立即学习“PHP免费学习笔记(深入)”;
-
xdebug.max_nesting_level(Xdebug启用时,默认仅100层) -
zend_extension加载后可能隐式降低栈容限 - CLI模式下系统级栈限制(Linux可用
ulimit -s查)
验证方式:var_dump(xdebug_get_max_nesting_level());。若返回100,哪怕你设了 memory_limit=2G,factorial(200) 仍会报错。
要用高精度大阶乘?绕过int,用BCMath或GMP
PHP原生整型在64位系统上最大约 9E18,factorial(21) 就溢出了。想算 factorial(100) 的完整数字,必须切换计算引擎:
// 用 BCMath(无需额外扩展,但慢)
function bcfactorial($n) {
$r = '1';
for ($i = 2; $i <= $n; $i++) {
$r = bcmul($r, (string)$i);
}
return $r;
}
-
bcmul参数必须是字符串,传整数会截断精度 - GMP更快(
gmp_mul),但需确认服务器启用了gmp扩展 - 输出仍是字符串——别试图用
(int)强转,会变0或科学计数法
Web环境跑阶乘?先想清楚为什么需要
真实项目中,前端点一下就要算 factorial(5000),基本等于主动拒绝服务。PHP是同步阻塞模型,这个请求会独占一个FPM进程几十毫秒甚至更久。
- 如果是密码学场景(如生成大素数),直接用现成库(
paragonie/random_compat) - 如果是数学教学演示,前端用JS算(
BigInt支持到任意精度),PHP只做校验 - 真要服务端算,加缓存(
factorial(100)结果永远不变)或异步队列(Redis + worker)
最常被忽略的一点:阶乘结果的位数增长极快——factorial(1000) 有2568位数字,光是字符串分配和拼接就比计算本身更耗资源。











