Урок 4. Циклы foreach, for, while в PHP
Теория
Циклы используются для того, чтобы некоторый участок кода выполнился несколько раз подряд.
Зачем это нужно - представьте, что вам нужно возвести в квадрат 100 элементов массива. Если обращаться к каждому элементу отдельно по его ключу - это займет 100 строчек кода, и для того, чтобы написать этот код, нужно будет потратить довольно много времени.
Но это не нужно - у нас есть возможность сделать так, чтобы PHP выполнил за нас некоторую операцию нужное количество раз. Например, возвел все элементы массива в квадрат.
Делается это с помощью циклов.
Есть 3 вида циклов: foreach, while и for. Давайте разберемся, как с ними работать и чем они отличаются друг от друга.
Цикл foreach
Цикл foreach используется для прохождения по всем элементам массива.
Синтаксис такой: пишется ключевое слово foreach, а после него круглые скобки (). В этих скобках указывается переменная, в которой лежит массив, потом слово as, а после него - переменная, в которую при каждом проходе цикла будет ложится элемент массива.
К примеру, это может выглядеть так - foreach($a as$e), где $a - это массив, а в переменную $e будут ложиться элементы массива.
После команды foreach() должны идти фигурные скобки {}. Код, который лежит в этих скобках, называется телом цикла.
Этот код будет выполняться столько раз, сколько проходов сделает цикл. А он сделает столько проходов, сколько элементов у нашего массива.
Итак, синтаксис цикла foreach выглядит так:
<?foreach($a - имя_массива as$e - переменная_для_элемента_массива){//Код, который находится между фигурными скобками будет повторяться столько раз, сколько элементов у массива.}
?>
Давайте решим следующую задачу: пусть дан массив $a с 5 элементами, выведем столбец этих элементов с помощью цикла foreach.
Будем при каждом проходе цикла выводить на экран (с помощью echo) текущий элемент массива (тот, что лежит в переменной $elem):
<?$a=[1,2,3,4,5];//Этот массив дан
foreach($a as$e)//Код, который находится между фигурными скобками будет повторяться столько раз, сколько элементов у массива (т.е. 5 раз).
{//В переменной $e будет лежать элемент массива, каждый раз разный: сначала 1-й, потом 2-й… Имя этой переменной обязательно должно отличаться от названия массива!
echo'<p>'.$e;//При каждом проходе цикла на экран будет выводится элемент массива, получится столбец элементов нашего массива $a=[1,2,3,4,5].
}?>
Цикл foreach - очень мощная и полезная вещь, его следует использовать в том случае, если вам необходимо выполнить какие-либо действия с каждым элементом массива по отдельности, например, возвести их в квадрат:
<?//Возведем в квадрат каждый элемент следующего массива:
$a=[1,2,3,4,5];foreach($a as$e){//В переменной $e будет лежать элемент массива, каждый раз разный: сначала 1, потом 2…
echo$e*$e;}?>
Циклом foreach можно пробегать не только по обычному массиву, но и по ассоциативному. В таком случае после as следует указать такую конструкцию: $ключ=>$элемент. В переменной $ключ будут хранится ключи, а в переменной $элемент - соответствующие этим ключам элементы.
Чтобы посмотреть на практике, как работать с ключами, давайте сделаем следующее - при каждом проходе цикла будем выводить на экран ключ массива и соответствующий ему элемент через дефис:
<?//Дан ассоциативный массив $arr:
$a=['a'=>1,'b'=>2,'c'=>3,'d'=>4,'e'=>5];foreach($a as$k=>$e){//В переменной $e будут лежать элементы массива сначала 1, потом 2 и т.д., а в переменной $k будут лежать ключи массива сначала 'a', потом 'b' и т.д.:
echo$k.'-'.$e;//Выведет: 'a-1','b-2','c-3' и т.д.
}?>
Если вам нужны только значения ассоциативного массива и не нужны ключи, то $ключ=> можно не писать:
<?//Массив ассоциативный, но ключи нам не нужны:
$a=['a'=>1,'b'=>2,'c'=>3,'d'=>4,'e'=>5];foreach($a as$e){echo$elem;//Выведет: '1','2','3' и т.д.
}?>
Фигурные скобки, так же, как и для if, можно не указывать - в этом случае цикл выполнит только 1 строку под ним (это относится ко всем циклам, не только к foreach):
<?$a=['a'=>1,'b'=>2,'c'=>3,'d'=>4,'e'=>5];foreach($a as$e)
echo$e;//Выведет: '1','2','3' и т.д.
echo'hello'//Выведется после цикла
?>
Цикл foreach имеет альтернативный синтаксис:
<?//Фигурные скобки опущены, а цикл закрывается командой endforeach:
$a=['a'=>1,'b'=>2,'c'=>3,'d'=>4,'e'=>5];foreach($a as$e)://обратите внимание на двоеточие!
echo$e;//Выведет: '1','2','3' и т.д.
endforeach?>
Как и в случае с конструкцией if-else, мы можем разорвать скобки PHP внутри цикла, далее написать что-то на HTML и опять открыть скобки PHP - в этом случае HTML код внутри цикла повторится столько раз, сколько проходов сделает цикл (в случае foreach - это количество элементов массива):
Как работать с HTML (этого многие не знают, обратите внимание!):
<?$a=['a'=>1,'b'=>2,'c'=>3,'d'=>4,'e'=>5];foreach($a as$e){//HTML код внутри цикла повторится 5 раз:
?>
Мы закрыли скобки PHP и теперь пишем на HTML, но в цикле!
{<?echo$e?>}
<?}?>
Альтернативный синтаксис (удобен при работе с html, так как не нужны фигурные скобки):
<?$a=['a'=>1,'b'=>2,'c'=>3,'d'=>4,'e'=>5];foreach($a as$e)://не забываем ставить двоеточие!
?>
{<?echo$e?>}
<?endforeach?>
Цикл while
Цикл while будет выполняться до тех пор, пока верно (истинно) выражение, переданное ему параметром. Смотрите синтаксис:
<?while(пока выражение истинно){тут пишется код, который выполнится много раз;}//В начале каждого прохода цикла PHP проверяет выражение в круглых скобках: если оно верно, выполняет следующий проход цикла, а если неверно, - цикл завершает свою работу. Т.е. цикл закончится, когда выражение перестанет быть истинным. Если оно было ложным изначально, то он не выполнится ни разу.
//Как и для foreach есть альтернативный синтаксис:
while(пока выражение истинно):тут пишется код, который выполнится много раз;
endwhile;?>
Вывести с помощью цикла while столбец цифр от 1 до 5.
Для этого введем переменную $i, которую будем использовать для того, чтобы остановить наш цикл.
Перед циклом переменной $i ставится значение 1, а внутри цикла будем при каждом проходе цикла увеличивать ее на 1. Сначала она будет 1, потом 2, потом 3 и т.д.
В условии окончания цикла поставим $i<=5 - это значит, что пока $i будет меньше или равна 5, цикл будет работать, а как только она станет 6, цикл закончит свою работу.
Используется переменная $i, чтобы считать количество проходов цикла. Однако, можно также воспользоваться ей для вывода нужного нам столбца чисел от 1 до 5. Просто при каждом проходе цикла выводится содержимое $i. Т.к. $i каждый раз увеличивается на 1, то сначала на экран выведется 1, потом 2 и т.д. до 5.
Вот код:
<?$i=1;//Начальное значение переменной $i
while($i<=5){//Цикл закончится, когда $i станет больше 5
//Выводится значение переменной $i на экран при каждом проходе цикла:
echo'<p>'.$i;//С помощью оператора ++ увеличиваем $i на 1 при каждом проходе цикла:
$i++;}?>
Переменная $i является счетчиком цикла. Счетчики используются для того, чтобы выполнить цикл нужное количество раз.
Кроме того они выполняют вспомогательную роль. В нашей задаче мы использовали счетчик, чтобы вывести цифры от 1 до 5 (и при этом для того, чтобы остановить цикл после 5 проходов).
Для счетчиков принято использовать буквы i, j, k.
Бесконечный цикл
Цикл while может выполняться бесконечно (но это приведет к зависанию скрипта!), достаточно передать ему выражение, которое никогда не станет ложным. Например, так:
<?$v=true;while($v===true){//Написанный здесь код будет выполняться вечно, пока скрипт не будет остановлен принудительно. Не стоит это повторять, это приведет к зависанию сервера!
}?>
Вместо $v===true можно написать сокращенный вариант, просто $v (так же, как и сокращенный вариант для if):
<?$v=true;while($v){//Написанный здесь код будет выполняться вечно, пока скрипт не будет остановлен принудительно. Не стоит это повторять, это приведет к зависанию сервера!
}?>
А можно вообще не вводить переменную $v, а в круглых скобках написать true:
<?while(true){//Написанный здесь код будет выполняться вечно, пока скрипт не будет остановлен принудительно. Не стоит это повторять, это приведет к зависанию сервера!
}?>
Бесконечный цикл может получится не намеренно, как в примерах выше, а случайно. К примеру, я могу задать такое условие окончания цикла, которое никогда не будет достигнуто.
Посмотрите на следующий пример, в нем начальное значение $i равно 1, в цикле оно каждый раз увеличивается на 1, т.е. $i будет расти: сначала 1, потом 2, потом 3…
А условие окончания цикла такое: $i>=1. Т.е. пока $i больше или равна 1, цикл будет крутиться. В нашем случае это будет вечно (так как $i растет и никогда не станет меньше 1):
<?$i=1;while($i>=1){//Написанный здесь код будет выполняться вечно, пока скрипт не будет остановлен принудительно. Не стоит это повторять - это приведет к зависанию сервера!
$i++;}?>
Цикл for
Цикл for является альтернативой while. Он более сложен для понимания, но его любят больше, чем while, за то, что он занимает меньше строчек.
Его синтаксис выглядит так:
<?for(начальные команды;условие окончания цикла;команды после прохода цикла){тело цикла}
?>
Начальные команды - это то, что выполнится перед стартом цикла. Они выполнятся только 1 раз. Обычно там размещают начальные значения счетчиков, пример: $i=0.
Условие окончания цикла - пока оно истинное, цикл будет работать, пример: $i<10.
Команды после прохода цикла - это команды, которые будут выполнятся каждый раз при окончании прохода цикла. Обычно там увеличивают счетчики, например: $i++.
Вывести столбец чисел от 0 до 9 с помощью цикла for:
<?//В начале цикла $i будет равно 0, цикл будет выполнятся пока $i<10, после каждого прохода к $i прибавляется 1:
for($i=0;$i<10;$i++){echo'<p>'.$i;//Выведет 0, 1, …, 9
}?>
Цикл без тела
Фигурные скобки в циклах можно не указывать, в этом случае цикл выполнит только 1 строку под ним (не рекомендую так делать, часто приводит к ошибкам):
<?for($i=0;$i<10;$i++)//Точки с запятой нет
echo$i;//Выведет 0, 1, …, 9
?>
А вот если после ) поставить точку с запятой, цикл закроется и следующая строка в него не попадет, получится так называемый цикл без тела, который в нашем случае просто прокрутится и в результате изменит значение переменной $i:
<?for($i=0;$i<10;$i++);//Точка с запятой есть
echo$i;//Выведет 9
?>
Такой цикл иногда используется, вы увидите примеры его применения при разборах задач на циклы.
Несколько команд в цикле for
Если нам необходимо выполнить несколько команд в круглых скобках, указываем их через запятую:
<?for($i=0,$j=2;$i<10;$i++,$j++,$i=$i+$j){}?>
Давайте разберем приведенный цикл: до прохода цикла выполнятся 2 команды: $i=0, $j=2, а после каждой итерации - целых 3: $i++,$j++,$i=$i+$j.
Этот пример с точки зрения программирования никакой особой пользы не несет, просто схематически показывает, что так можно делать. Запомните его, в дальнейшем это вам пригодится.
Инструкция break
Иногда нам необходимо прервать выполнение цикла досрочно, в случае с циклом foreach это значит до того, как цикл переберет все элементы массива.
Зачем такое может понадобится? Например, перед нами стоит задача выводить элементы массива до тех пор, пока не встретится число 3. Как только встретится, цикл должен завершить свою работу.
Такое можно сделать с помощью инструкции break. Если выполнение цикла дойдет до нее, цикл закончит свою работу.
Давайте решим приведенную выше задачу: оборвем цикл, как только нам встретится число 3:
<?$a=[1,2,3,4,5];foreach($a as$e){if($e===3)
break;//выходим из цикла
else echo$e;}?>
Инструкция continue
Существует также инструкция continue, при достижении которой цикл начинает новую итерацию. Иногда может быть полезна для упрощения кода, хотя практически всегда задачу можно решить и без нее.
Практика
Примеры решения задач
Задача
Дан массив с элементами 'html','css','php','js','jq'. С помощью цикла foreach вывести эти слова в столбик.
Решение: Для начала необходимо создать сам массив. В данном случае мы можем воспользоваться различными способами: объявить через [] либо просто воспользоваться присваиванием $a[]='html';$a[]='php'; и т.д. Я выбрал 1-й способ, т.к. он занимает меньше места при записи:
<?$a=['html','css','php','js','jq']?>
Теперь необходимо воспользоваться циклом foreach:
<?$a=['html','css','php','js','jq'];foreach($a as$e){echo'<p>'.$e;}?>
Как это все работает: в переменной $e все элементы будут лежать по порядку (сначала 'html', потом 'css' и т.д.). Они выводятся их на экран с помощью echo.
Задача
Дан массив с элементами 10,20,15,17,24,35. Найти сумму элементов этого массива. Записать ее в переменную $r.
Решение: 1-е решение, которое может прийти в голову - это просуммировать все элементы массива 'руками': $a[0]+$a[1]+…+$a[5].
Этот способ неправильный, т.к. в случае изменения массива код придется переписывать (например, в него добавится еще 88 элементов, что будет печально). Решение необходимо делать как можно более универсальным.
Поэтому мы должны воспользоваться циклом foreach, в этом случае нет привязки к количеству элементов массива.
Теперь нужно подумать о том, как просуммировать элементы массива в цикле. Для этого вводится переменная $r, к которой при каждом проходе цикла прибавляется она сама и еще 1 элемент массива таким образом $r=$r+$e:
<?$a=[10,20,15,17,24,35];$r=0;foreach($a as$e){$r=$r+$e;}
echo$r//Вывод суммы на экран
?>
В строке $r=0 зануляется переменная $r, если этого не сделать, в цикле возникнет ошибка в строке $r=$r+$e, т.к. при 1-м проходе цикла переменная $r не будет определена.
Как работает строка $r=$r+$e: при 1-м проходе в переменной $r будет 0, в $e - 10 (1-й элемент массива), тогда в $r запишется 0+10=10.
При 2-м проходе цикла в $r лежит уже 10 (значение из прошлого прохода цикла), а в $e лежит 20 (следующий элемент массива), тогда в $r запишется 10+20=30.
При 3-м проходе цикла в $r лежит 30, а в $e - 15, в $r запишется 30+15=45. И т.д., пока цикл не закончится.
Строку $r=$r+$e можно записать короче: $r+=$e.
Задача
Вывести столбец чисел от 1 до 100.
Решение: Задачу можно решить как циклом for, так и циклом while. Вначале решим через цикл while:
<?$i=1;//Счетчик цикла устанавливаем в 1
while($i<=100){echo'<p>'.$i;//Выведет 1,2,…,100
$i++;//С помощью оператора ++ увеличивается $i на 1 при каждом проходе цикла:
}?>
Решение через цикл for:
<?//В начале цикла $i будет равно 1, цикл будет выполняться, пока $i<=100, после каждого прохода к $i прибавляется 1:
for($i=1;$i<=100;$i++){echo'<p>'.$i;//Выведет 1,2,…,100
}?>
Задачи для решения
Работа с foreach
Дан массив с элементами 'html','css','php','js','jq'. С помощью цикла foreach вывести эти слова в столбик.
Дан массив с элементами 1,2,3,4,5. С помощью цикла foreach найти сумму элементов этого массива. Записать ее в переменную $r.
Дан массив с элементами 1,2,3,4,5. С помощью цикла foreach найти сумму квадратов элементов этого массива. Результат записать переменную $r.
Работа с ключами
Дан массив $a. С помощью цикла foreach вывести на экран столбец ключей и элементов в формате 'green - зеленый'.
$a=['green'=>'зеленый','red'=>'красный','blue'=>'голубой'];
Дан массив $a с ключами 'Коля','Вася','Петя' и с элементами '200','300','400'. С помощью цикла foreach вывести на экран столбец строк такого формата: 'Коля - зарплата 200 долларов.'.
Циклы while и for
Решать эти задачи сначала через цикл while, а затем через цикл for.
Вывести столбец чисел от 1 до 100.
Вывести столбец чисел от 11 до 33.
Вывести столбец четных чисел в промежутке от 0 до 100.
С помощью цикла найти сумму чисел от 1 до 100.
Задачи
Дан массив с элементами 2,5,9,15,0,4. С помощью цикла foreach и оператора if вывести на экран столбец тех элементов массива, которые больше 3-х, но меньше 10.
Дан массив с числами. Числа могут быть положительными и отрицательными. Найти сумму положительных элементов этого массива.
Дан массив с элементами 1,2,5,9,4,13,4,10. С помощью цикла foreach и оператора if проверить есть ли в массиве элемент со значением, равным 4. Если есть - вывести на экран 'Есть!' и выйдите из цикла. Если нет - ничего делать не надо.
Дан массив числами, например: ['10','20','30','50','235','3000']. Вывести на экран только те числа из массива, которые начинаются на цифру 1, 2 или 5.
Дан массив с элементами 1,2,3,4,5,6,7,8,9. С помощью цикла foreach создать строку '-1-2-3-4-5-6-7-8-9-'.
Составить массив дней недели. С помощью цикла foreach вывести все дни недели, а выходные дни вывести жирным.
Составить массив дней недели. С помощью цикла foreach вывести все дни недели, а текущий день вывести курсивом. Текущий день должен храниться в переменной $day.
Задачи посложнее
С помощью цикла for заполнить массив числами от 1 до 100. Т.е. должен получится массив [1,2,…,100].
Дан массив $a. С помощью цикла foreach записать английские названия в массив $e, а русские - в массив $r.
$a=['green'=>'зеленый','red'=>'красный','blue'=>'голубой'];
Дано число $n=1000. Делить его на 2 столько раз, пока результат деления не станет меньше 50. Какое число получится? Посчитайте количество итераций, необходимых для этого (итерация - это проход цикла). Решать задачу сначала через цикл while, а потом через цикл for.