在嵌套循环中使用数组耗尽内存
Memory exhausted using an array in a nested loop
这是我遇到的错误。
Fatal Error: Allowed memory size exhausted.
我正在获取包含日期 from
和日期 till
的数组。我正在尝试获取介于两者之间的所有日期并将它们添加到新数组中。显然嵌套循环和多数组很累。
我需要一种不那么费力的方法来获取所有日期。
这是我的代码:
$query = "SELECT *
FROM reservate
ORDER BY from";
$result = $connect->query($query);
$reservations = array();
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
$reservations[] = $row;
}
}
$connect->close();
//AVAILABILITY CHECK
$nonAvailable = array();
foreach($reservations as $reservation){
$from = $reservation['from'];
$till = $reservation['till'];
while($from <= $till){
$nonAvailable[] = $from;
$from = date('Y-m-d', strtotime("+1 days"));
}
}
看起来你做了一个无限循环1.
// if $till is in the future, this is an infinite loop
while($from <= $till){
// appending the same value of $from on each iteration
$nonAvailable[] = $from;
// as $from never changes value
$from = date('Y-m-d', strtotime("+1 days"));
}
将 1
天添加到 $from
的当前值
while ($from <= $till){
$nonAvailable[] = $from;
// add 1 day to $from
$from = date('Y-m-d', strtotime($from, "+1 days"));
}
还有一些可以改进的地方:
-
在以下示例中,整个 table 未复制到
reservation
数组,我们只检索我们需要的列
来自 table。
-
比较
integers
而不是 strings
。
-
手动将
1
天添加到 $from
而不是依靠 strtotime
来完成。
$query = "SELECT from, till
FROM reservate
ORDER BY from";
$result = $connect->query($query);
$nonAvailable = array();
if ($result->num_rows > 0) {
while ($row = $result->fetch_assoc()) {
$from = strtotime($row['from']);
$till = strtotime($row['till']);
while ($from <= $till) {
$nonAvailable[] = date('Y-m-d', $from);
$from += 60*60*24;
}
}
}
$connect->close();
很可能可以使该算法更加高效。例如,您是否需要一份包含每天保留内容的详尽清单?如果不是,那么只需开始日期和结束日期就足够了。
1 如果有足够的时间和内存,循环将退出,因为 strtotime("+1 days")
最终会 return 一个大于 $till
的值。
另一种方法,只使用一个查询。
这需要您的预订 table 并将其与几个获取数字范围的子查询交叉连接。每人得到0到9的数字,一个为个位,一个为十位。将它们组合在一起会给你数字 0 到 99(所以 99 天范围)。
WHERE 子句只检查开始日期 (van) 加上天数(从 0 到 99)小于或等于结束日期 (tot)。因此,一个房间(我假设是多个房间,或者其他一些被预订出去的项目)在每个预订日期都会被淘汰:-
SELECT room, DATE_ADD(van, INTERVAL (tens.i * 10 + units.i) DAY) AS non_available
FROM reservate
CROSS JOIN (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) units
CROSS JOIN (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) tens
WHERE DATE_ADD(van, INTERVAL (tens.i * 10 + units.i) DAY) <= tot
ORDER BY room, non_available
SQL fiddle 示例:-
http://www.sqlfiddle.com/#!9/83054/1
您可以使用 table 个整数来代替 2 个子查询。
这是我遇到的错误。
Fatal Error: Allowed memory size exhausted.
我正在获取包含日期 from
和日期 till
的数组。我正在尝试获取介于两者之间的所有日期并将它们添加到新数组中。显然嵌套循环和多数组很累。
我需要一种不那么费力的方法来获取所有日期。
这是我的代码:
$query = "SELECT *
FROM reservate
ORDER BY from";
$result = $connect->query($query);
$reservations = array();
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
$reservations[] = $row;
}
}
$connect->close();
//AVAILABILITY CHECK
$nonAvailable = array();
foreach($reservations as $reservation){
$from = $reservation['from'];
$till = $reservation['till'];
while($from <= $till){
$nonAvailable[] = $from;
$from = date('Y-m-d', strtotime("+1 days"));
}
}
看起来你做了一个无限循环1.
// if $till is in the future, this is an infinite loop
while($from <= $till){
// appending the same value of $from on each iteration
$nonAvailable[] = $from;
// as $from never changes value
$from = date('Y-m-d', strtotime("+1 days"));
}
将 1
天添加到 $from
while ($from <= $till){
$nonAvailable[] = $from;
// add 1 day to $from
$from = date('Y-m-d', strtotime($from, "+1 days"));
}
还有一些可以改进的地方:
-
在以下示例中,整个 table 未复制到
reservation
数组,我们只检索我们需要的列 来自 table。 -
比较
integers
而不是strings
。 -
手动将
1
天添加到$from
而不是依靠strtotime
来完成。
$query = "SELECT from, till
FROM reservate
ORDER BY from";
$result = $connect->query($query);
$nonAvailable = array();
if ($result->num_rows > 0) {
while ($row = $result->fetch_assoc()) {
$from = strtotime($row['from']);
$till = strtotime($row['till']);
while ($from <= $till) {
$nonAvailable[] = date('Y-m-d', $from);
$from += 60*60*24;
}
}
}
$connect->close();
很可能可以使该算法更加高效。例如,您是否需要一份包含每天保留内容的详尽清单?如果不是,那么只需开始日期和结束日期就足够了。
1 如果有足够的时间和内存,循环将退出,因为 strtotime("+1 days")
最终会 return 一个大于 $till
的值。
另一种方法,只使用一个查询。
这需要您的预订 table 并将其与几个获取数字范围的子查询交叉连接。每人得到0到9的数字,一个为个位,一个为十位。将它们组合在一起会给你数字 0 到 99(所以 99 天范围)。
WHERE 子句只检查开始日期 (van) 加上天数(从 0 到 99)小于或等于结束日期 (tot)。因此,一个房间(我假设是多个房间,或者其他一些被预订出去的项目)在每个预订日期都会被淘汰:-
SELECT room, DATE_ADD(van, INTERVAL (tens.i * 10 + units.i) DAY) AS non_available
FROM reservate
CROSS JOIN (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) units
CROSS JOIN (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) tens
WHERE DATE_ADD(van, INTERVAL (tens.i * 10 + units.i) DAY) <= tot
ORDER BY room, non_available
SQL fiddle 示例:-
http://www.sqlfiddle.com/#!9/83054/1
您可以使用 table 个整数来代替 2 个子查询。