PHP嵌套for循环中DateTime值被覆盖致输出异常求助
嵌套循环中DateTime对象的引用问题分析与修复
问题根源
你猜的没错,问题出在PHP的DateTime是引用类型,赋值时传递的是对象引用而非副本:
- 外层循环中,
$i = $begin_from让$i指向原$begin_from对象,每次modify会修改原对象,但外层循环还能正常迭代,因为每次+1月直到超过$end_from。 - 内层循环中,
$k = $begin_to直接让$k指向原$begin_to对象,第一次内层循环执行时,每次modify都会直接修改$begin_to本身。当第一次内层循环跑完,$begin_to已经被修改为2024-01-31(超出$end_to的范围),后续外层循环迭代时,内层循环的初始条件$k <= $end_to直接不成立,所以只会输出第一次外层循环的结果。
修复方案
需要在每次进入内层循环时,创建$begin_to的独立副本,使用clone关键字即可(DateTime对象支持克隆):
<?php $begin_from = new DateTime("2023-01-01"); $end_from = new DateTime("2023-12-31"); $begin_to = new DateTime("2023-01-31"); $end_to = new DateTime("2023-12-31"); for($i = $begin_from; $i <= $end_from; $i->modify('+1 month')){ // 每次内层循环克隆原对象,避免修改$begin_to的初始值 $current_to = clone $begin_to; for($k = $current_to; $k <= $end_to; $k->modify('first day of')->modify('+1 month')->modify('last day of')){ echo $i->format("Y-m-d"),'..',$k->format("Y-m-d"); echo "\n"; } }
更简洁的实现方式
如果你的需求是输出每个月的1号到当月月末,完全可以直接基于$i的月份计算月末,不需要单独维护$begin_to,代码更简洁:
<?php $begin_from = new DateTime("2023-01-01"); $end_from = new DateTime("2023-12-31"); // 克隆初始对象,避免修改原$begin_from for($i = clone $begin_from; $i <= $end_from; $i->modify('+1 month')){ $month_end = clone $i; $month_end->modify('last day of this month'); echo $i->format("Y-m-d"),'..',$month_end->format("Y-m-d"); echo "\n"; }
内容的提问来源于stack exchange,提问作者samz
相关产品推荐
相关产品推荐

