PHP7下Laravel日期过滤报错,PHP5.6正常的问题排查与修复
解决PHP7 Laravel中“Only variables should be passed by reference”错误
嘿,这个问题我太熟悉了——同样的代码在PHP5.6纯环境里跑完全正常,到PHP7的Laravel项目就报错,核心原因是PHP7对参数传递的规则做了更严格的约束。咱们一步步来拆解:
问题重现
你遇到的错误提示是Only variables should be passed by reference,报错的代码行是:
$result[array_pop(array_keys($result))][] = $val;
你的完整业务代码如下:
public function filter(Request $request) { $time = new DateTime('now'); $now = $time->modify('first day of this month')->format('Y-m-d'); $last_year = $time->modify('-1 year')->format('Y-m-d'); // get a list of dates from past year $all = $this->dateRange($last_year, $now); foreach($request->dates as $date) { // get date ranges of completed addresses $range = $this->dateRange($date[0], $date[1]); // return an array of unconfirmed dates for addresses $all = array_diff($all, $range); } if(empty($all)) { $time = new DateTime('now'); $now = $time->format('M Y'); $last_year = $time->modify('-1 year')->format('M Y'); $dates[] = array( $last_year, $now ); } else { $time = new DateTime('now'); $last_year = $time->modify('first day of this month')->modify('-1 year'); $result = array(); foreach ($all as $key => $val) { if ($last_year->add(new DateInterval('P1D'))->format('Y-m-d') != $val) { $result[] = array(); $last_year = new DateTime($val); } $result[array_pop(array_keys($result))][] = $val; } foreach($result as $array) { $dates[] = array( (new DateTime($array[0]))->format('M Y'), (new DateTime(end($array)))->format('M Y') ); } } return response()->json($dates); } private function dateRange($start, $end) { $period = new DatePeriod( new DateTime($start), new DateInterval('P1D'), new DateTime($end) ); foreach($period as $key => $value) { $range[] = $value->format('Y-m-d'); } return $range; }
错误原因
PHP7收紧了引用传递参数的规则:像array_pop()这类函数,要求传入的参数必须是一个可被引用的变量,因为函数内部会修改这个参数(移除数组最后一个元素)。
在PHP5.6里,允许你直接把array_keys($result)这种临时表达式(它返回的是一个全新的临时数组,不是存在内存里的变量)传给array_pop();但PHP7开始明确禁止这种写法——临时表达式无法被引用,所以就抛出了这个错误。
修复方案
有两种靠谱的修复方式,推荐第二种,性能更好代码也更清晰:
方式1:先把临时数组转为变量
把array_keys($result)的结果先存到一个变量里,再传给array_pop():
// 替换原来的报错行 $resultKeys = array_keys($result); $lastResultKey = array_pop($resultKeys); $result[$lastResultKey][] = $val;
方式2:直接跟踪最后一个子数组的键名(更高效)
你的逻辑是往$result的最后一个子数组里追加元素,完全没必要每次都生成整个数组的键列表。咱们可以在初始化时跟踪最后一个子数组的键名:
// 初始化$result时,同时跟踪最后一个子数组的键 $result = array(); $lastSubarrayKey = -1; foreach ($all as $key => $val) { if ($last_year->add(new DateInterval('P1D'))->format('Y-m-d') != $val) { $result[] = array(); $lastSubarrayKey++; // 新增子数组,键名+1 $last_year = new DateTime($val); } // 直接用跟踪的键名访问最后一个子数组 $result[$lastSubarrayKey][] = $val; }
这种方式避免了每次循环都调用array_keys()和array_pop(),性能更优,逻辑也更直观。
另外,代码里(new DateTime(end($array)))->format('M Y')这行,虽然现在没报错,但end()同样要求参数是变量引用,为了稳妥可以提前存变量:
$lastDateInArray = end($array); (new DateTime($lastDateInArray))->format('M Y')
内容的提问来源于stack exchange,提问作者Peter Griffin
相关产品推荐
相关产品推荐

