PHP时间判断公交服务类型异常问题及简化方案咨询
我希望根据页面当前时间输出客运公司的服务类型,服务类型包括“Semidirecte (sd)”、“Pobles (p)”和“Exprés (e)”。我编写了基于DateTime类的PHP时间判断代码,但线上站点的显示结果不符合预期。以下是我的代码:
<?php $now = new DateTime(); $v0600 = new DateTime('6:00'); $v0630 = new DateTime('6:30'); $v0650 = new DateTime('6:50'); $v0705 = new DateTime('7:05'); $v0725 = new DateTime('7:25'); $v0755 = new DateTime('7:55'); $v0825 = new DateTime('8:25'); $v0840 = new DateTime('8:40'); $v0900 = new DateTime('9:00'); $v0925 = new DateTime('9:25'); $v1000 = new DateTime('10:00'); $v1020 = new DateTime('10:20'); $v1030 = new DateTime('10:30'); $v1115 = new DateTime('11:15'); $v1200 = new DateTime('12:00'); $v1210 = new DateTime('12:10'); $v1230 = new DateTime('12:30'); $v1300 = new DateTime('13:00'); $v1325 = new DateTime('13:25'); $v1400 = new DateTime('14:00'); $v1435 = new DateTime('14:35'); $v1450 = new DateTime('14:50'); $v1505 = new DateTime('15:05'); $v1525 = new DateTime('15:25'); $v1600 = new DateTime('16:00'); $v1620 = new DateTime('16:20'); $v1635 = new DateTime('16:35'); $v1700 = new DateTime('17:00'); $v1725 = new DateTime('17:25'); $v1805 = new DateTime('18:05'); $v1820 = new DateTime('18:20'); $v1835 = new DateTime('18:35'); $v1910 = new DateTime('19:10'); $v2000 = new DateTime('20:00'); $v2100 = new DateTime('21:00'); $v2125 = new DateTime('21:25'); $v2155 = new DateTime('21:55'); $v2210 = new DateTime('22:10'); $v2305 = new DateTime('23:05'); $v0500 = new DateTime('05:00'); $sd = Semidirecte; $p = Pobles; $e = Exprés; if ($now > $v0500 && $now < $v0600 or $now > $v0630 && $now < $v0650 or $now > $v0840 && $now < $v0900 or $now > $v0925 && $now < $v1000 or $now > $v1115 && $now < $v1200 or $now > $v1325 && $now < $v1400 or $now > $v1525 && $now < $v1600 or $now > $v1635 && $now < $v1700 or $now > $v1725 && $now < $v1805 or $now > $v1910 && $now < $v2000 or $now > $v2035 && $now < $v2100 or $now > $v2125 && $now < $v2155){ echo $sd; } elseif ($now > $v0650 && $now < $v0705 or $now > $v0825 && $now < $v0840 or $now > $v1000 && $now < $v1020 or $now > $v1200 && $now < $v1210 or $now > $v1230 && $now < $v1300 or $now > $v1435 && $now < $v1450 or $now > $v1450 && $now < $v1505 or $now > $v1600 && $now < $v1620 or $now > $v1805 && $now < $v1820 or $now > $v2000 && $now < $v2010 or $now > $v2155 && $now < $v2210){ echo $e; } elseif ($now > $v0600 && $now < $v0630 or $now > $v0705 && $now < $v0725 or $now > $v0725 && $now < $v0755 or $now > $v0755 && $now < $v0825 or $now > $v0900 && $now < $v0925 or $now > $v1020 && $now < $v1030 or $now > $v1030 && $now < $v1115 or $now > $v1210 && $now < $v1230 or $now > $v1300 && $now < $v1325 or $now > $v1400 && $now < $v1435 or $now > $v1505 && $now < $v1525 or $now > $v1620 && $now < $v1635 or $now > $v1700 && $now < $v1725 or $now > $v1820 && $now < $v1835 or $now > $v1835 && $now < $v1910 or $now > $v2010 && $now < $v2035 or $now > $v2100 && $now < $v2125 or $now > $v2210 && $now < $v2305){ echo $p; } else { echo "No data"; } ?>
请问我的代码存在什么问题?是否有更简洁的实现方案?
一、你的代码存在的几个关键问题
字符串未加引号,触发常量解析错误
你定义服务类型时直接写了$sd = Semidirecte;,这里的Semidirecte会被PHP当作常量处理,如果没有提前定义这个常量,PHP会抛出警告并将其当作字符串字面量处理(这是历史兼容行为,但非常不可靠)。正确的写法应该给字符串加上单引号或双引号:$sd = 'Semidirecte (sd)'; $p = 'Pobles (p)'; $e = 'Exprés (e)';逻辑运算符优先级错误
or的优先级比&&低,导致你的条件判断逻辑会出现意外结果。比如$now > $v0500 && $now < $v0600 or $now > $v0630 && $now < $v0650虽然看起来没问题,但复杂组合下容易出错。建议统一使用||替代or,或者给每个时间区间的条件加上括号,确保逻辑符合预期。未定义的时间变量
你的条件中用到了$v2035和$v2010,但代码里并没有初始化这两个DateTime对象,这会导致PHP抛出“Undefined variable”的错误,直接影响判断结果。时间区间覆盖不全、存在重叠
- 边界时间点(比如刚好6:00、6:30)没有被包含在任何区间内,会直接落到
else分支输出"No data"。 - 部分区间存在重复判断,比如
$now > $v0725 && $now < $v0755和前面的$now > $v0705 && $now < $v0725是连续区间,但写法冗余,还可能出现遗漏。
- 边界时间点(比如刚好6:00、6:30)没有被包含在任何区间内,会直接落到
代码冗余,维护成本高
定义了几十个单独的DateTime变量,后续如果要调整时间区间,需要逐个修改,非常容易出错。
二、更简洁的实现方案
我们可以把时间区间和对应的服务类型整理成一个二维数组,然后遍历数组判断当前时间属于哪个区间,这样代码更清晰、易维护:
<?php // 定义时间区间与服务类型的映射关系 $serviceIntervals = [ ['start' => '05:00', 'end' => '06:00', 'type' => 'Semidirecte (sd)'], ['start' => '06:30', 'end' => '06:50', 'type' => 'Semidirecte (sd)'], ['start' => '08:40', 'end' => '09:00', 'type' => 'Semidirecte (sd)'], ['start' => '09:25', 'end' => '10:00', 'type' => 'Semidirecte (sd)'], ['start' => '11:15', 'end' => '12:00', 'type' => 'Semidirecte (sd)'], ['start' => '13:25', 'end' => '14:00', 'type' => 'Semidirecte (sd)'], ['start' => '15:25', 'end' => '16:00', 'type' => 'Semidirecte (sd)'], ['start' => '16:35', 'end' => '17:00', 'type' => 'Semidirecte (sd)'], ['start' => '17:25', 'end' => '18:05', 'type' => 'Semidirecte (sd)'], ['start' => '19:10', 'end' => '20:00', 'type' => 'Semidirecte (sd)'], ['start' => '20:35', 'end' => '21:00', 'type' => 'Semidirecte (sd)'], ['start' => '21:25', 'end' => '21:55', 'type' => 'Semidirecte (sd)'], ['start' => '06:50', 'end' => '07:05', 'type' => 'Exprés (e)'], ['start' => '08:25', 'end' => '08:40', 'type' => 'Exprés (e)'], ['start' => '10:00', 'end' => '10:20', 'type' => 'Exprés (e)'], ['start' => '12:00', 'end' => '12:10', 'type' => 'Exprés (e)'], ['start' => '12:30', 'end' => '13:00', 'type' => 'Exprés (e)'], ['start' => '14:35', 'end' => '14:50', 'type' => 'Exprés (e)'], ['start' => '14:50', 'end' => '15:05', 'type' => 'Exprés (e)'], ['start' => '16:00', 'end' => '16:20', 'type' => 'Exprés (e)'], ['start' => '18:05', 'end' => '18:20', 'type' => 'Exprés (e)'], ['start' => '20:00', 'end' => '20:10', 'type' => 'Exprés (e)'], ['start' => '21:55', 'end' => '22:10', 'type' => 'Exprés (e)'], ['start' => '06:00', 'end' => '06:30', 'type' => 'Pobles (p)'], ['start' => '07:05', 'end' => '07:25', 'type' => 'Pobles (p)'], ['start' => '07:25', 'end' => '07:55', 'type' => 'Pobles (p)'], ['start' => '07:55', 'end' => '08:25', 'type' => 'Pobles (p)'], ['start' => '09:00', 'end' => '09:25', 'type' => 'Pobles (p)'], ['start' => '10:20', 'end' => '10:30', 'type' => 'Pobles (p)'], ['start' => '10:30', 'end' => '11:15', 'type' => 'Pobles (p)'], ['start' => '12:10', 'end' => '12:30', 'type' => 'Pobles (p)'], ['start' => '13:00', 'end' => '13:25', 'type' => 'Pobles (p)'], ['start' => '14:00', 'end' => '14:35', 'type' => 'Pobles (p)'], ['start' => '15:05', 'end' => '15:25', 'type' => 'Pobles (p)'], ['start' => '16:20', 'end' => '16:35', 'type' => 'Pobles (p)'], ['start' => '17:00', 'end' => '17:25', 'type' => 'Pobles (p)'], ['start' => '18:20', 'end' => '18:35', 'type' => 'Pobles (p)'], ['start' => '18:35', 'end' => '19:10', 'type' => 'Pobles (p)'], ['start' => '20:10', 'end' => '20:35', 'type' => 'Pobles (p)'], ['start' => '21:00', 'end' => '21:25', 'type' => 'Pobles (p)'], ['start' => '22:10', 'end' => '23:05', 'type' => 'Pobles (p)'], ]; $now = new DateTime(); $serviceType = "No data"; // 遍历区间判断 foreach ($serviceIntervals as $interval) { $start = new DateTime($interval['start']); $end = new DateTime($interval['end']); // 包含边界时间点,比如刚好等于start或end时也匹配 if ($now >= $start && $now <= $end) { $serviceType = $interval['type']; break; // 找到匹配的区间就停止遍历 } } echo $serviceType; ?>
这个方案的优势:
- 可读性强:所有时间区间和对应服务类型一目了然,后续调整只需修改数组即可。
- 逻辑清晰:遍历判断避免了复杂的多条件组合,减少逻辑错误概率。
- 易维护:新增或修改时间区间时,只需在数组中添加或修改一行数据,无需调整大量条件判断。
- 覆盖边界:使用
>=和<=确保边界时间点也能被正确匹配,不会落到else分支。
内容的提问来源于stack exchange,提问作者Pol Diloli

