Память исчерпана использованием массива во вложенном цикле

Это ошибка, которую я получаю.

Неустранимая ошибка: допустимый объем памяти исчерпан.

Я собираю массивы, содержащие дату 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"));
}
}

2

Решение

Похоже, вы сделали бесконечный цикл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"));
}

Есть еще несколько улучшений, которые можно сделать:

  • В следующем примере вся таблица не копируется в
    reservation массив и мы только извлекаем нужные нам столбцы
    из таблицы.
  • Сравнение 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") в конечном итоге вернет значение больше $till,

10

Другие решения

Альтернативный способ сделать это, используя только один запрос.

Это берет вашу таблицу бронирования и перекрестно соединяет ее с парой подзапросов, которые получают диапазоны чисел. Каждый получает числа от 0 до 9, и один используется как единицы, а один — как десятки. В сочетании они дают цифры от 0 до 99 (таким образом, диапазон 99 дней).

Предложение WHERE просто проверяет, что дата от даты (фургон) плюс количество дней (от 0 до 99) меньше или равна дате до (общая). Следовательно, комната (я предполагаю, что несколько комнат или какой-то другой предмет, который забронирован) выдается с каждой датой, когда она забронирована:

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: —

http://www.sqlfiddle.com/#!9/83054/1

Вы можете использовать таблицу целых чисел вместо 2 подзапросов.

1

По вопросам рекламы [email protected]