Source Code for /public/03-lists-and-loops/index.php
<?php
require('../inc/functions.php');
add_header('Lesson 3: Lists and Loops');
?>
<div class="objectives">
<h2>Objectives</h2>
<ul>
<li>Create a variable and assign it a value</li>
<li>Use a <code>for</code> loop to repeat a block of code a certain number of times</li>
<li>Use a <code>foreach</code> loop to iterate through each item in an array</li>
<li>Understand that arrays can be indexed by numbers (the default) or by strings</li>
<li>Use a <code>glob()</code> function to turn a list of files into an array</li>
</ul>
</div>
<h2 id="looping">Looping</h2>
<p>
PHP has several ways of looping through the same code several times.
A <code>for</code> loop lets you specify the number of times the loop should run. The
syntax is a little gnarly if you've not come across <code>for</code> loops in any
language before, but you'll get to grips with it with practice.
</p>
<p>
Let's create a new file called <code>7-times-table.php</code> to show off how well we
know our 7-times table:
</p>
<?php code_block_from_file( '03-lists-and-loops/7-times-table.php', 'php' ); ?>
<p>
Here's what's happening:
</p>
<ol>
<li>Our <code>for</code> loop creates a variable called <code>$i</code> and assign it the value 1</li>
<li>While the value of <code>$i</code> is less than or equal to 10, the code inside the <code>for</code> loop is executed, and then the value of <code>$i</code> is increased by 1 (<code>++</code>)</li>
<li>
We print out the question <code>"7 × $i = "</code>
<ul>
<li>
See how PHP lets us use the variable right in the middle of the string: this is called
<a href="https://www.php.net/manual/en/language.types.string.php#language.types.string.parsing">string interpolation</a>,
and it works for strings in double quotes (<code>"</code>) but not for strings in single quotes (<code>'</code>)
</li>
</ul>
</li>
<li>Then we calculate the answer <code>( 7 * $i )</code> and <code>echo</code> it out</li>
<li>Finally, we <code>echo</code> a HTML line break (<code><br></code>)</li>
</ol>
<p class="tip">
Doing your 7-times table up to ten sevens isn't so impressive, but what if you made it go to a hundred sevens. Or a thousand?
</p>
<p class="tip">
It's possible to put loops inside other loops. Can you work out how to print out all the 1-times tables, 2-times tables,
3-times tables, etc., up to 12-times-12? You'll need a loop inside another loop, with the "outer" loop using a different
variable name than the "inner" loop.
<small>(<a href="https://php.danq.dev/demo-harness.php?file=public/appendix-samples/times-tables-square.php">🏁 view solution</a>)</small>
</p>
<h2 id="looping-through-a-list">A basic gallery</h2>
<p>
Another kind of loop is the <code>foreach</code> loop. This iterates through each item in an array.
(An array is a kind of list of values.) Arrays in PHP can be defined either using square brackets (<code>[]</code>)
or the <code>array()</code> function: either way, the items in the array are separated by commas (<code>,</code>).
</p>
<p>
Here I've made an array listing different fruits. For each fruit
in the array, I exit my PHP code (<code>?></code>) to start writing HTML code. I write an <code><img></code>
tag for each fruit, using the fruit's name as part of the filename and to help write the alt-text:
</p>
<?php code_block_from_file( '03-lists-and-loops/loop-through-images.php', 'php' ); ?>
<p>
Loops are great when you want to do a very similar thing multiple times, like when you're outputting a list
of links or the images in a gallery.
</p>
<p class="tip">
Instead of showing each image, could you make an ordered list (<code><ol></code> and <code><li></code>) of
hyperlinks (<code><a href="...">...</a></code>) to each fruit's image?
<small>(<a href="https://php.danq.dev/demo-harness.php?file=public/appendix-samples/fruity-links.php">🏁 view solution</a>)</small>
</p>
<p>
By default, an array in PHP is indexed by numbers (starting from 0). If you wanted to print the name of <em>third</em> fruit
in the array, you could write <code><?php echo $images[2]; ?></code>. But it's also possible to index an array by
some other identifier, such as a string. This means it's possible to make an array like this:
</p>
<?php code_block_from_file( '03-lists-and-loops/string-keyed-array.php', 'php' ); ?>
<h2 id="navigation-menu">Making a navigation menu</h2>
<p>
Let's use what we know to write some PHP that prints out a navigation menu for our site. A navigation menu is a perfect
example of something that may require the same repetitive structure several times over:
</p>
<?php code_block_from_file( '03-lists-and-loops/navigation-menu.php', 'php', true, true, true ); ?>
<p class="tip">
<em>This site</em> uses a navigation menu like this, but with a few enhancements. If you're curious, you can
<a href="/source-viewer.php?file=public/inc/functions.php">view the source code</a> to see how it's done (look
in the <code>add_navbar()</code> function).
</p>
<p>
Because we're working in PHP code, we can edit our array dynamically. For example, we could add a link to
<a href="/02-hello-world/#conditional">the page we made that's closed on Mondays</a> to our navigation menu... but only
if it's not a Monday.
</p>
<p>
To do this, we use an <code>if</code> statement to check if today is Monday. If it isn't, we use PHP's
<code>[]=</code> operator to add a new link to our array (another option would be the
<a href="https://www.php.net/manual/en/function.array-push.php"><code>array_push()</code></a> function):
</p>
<?php code_block_from_file( '03-lists-and-loops/navigation-menu-2.php', 'php', true, true, true ); ?>
<p>
The same approach could be used to add menu items that are only visible to logged-in users, for example.
You'd still want to check if they're logged-in when they visit the page behind the link, of course, to prevent
them from simply typing its URL into their browser's address bar!
</p>
<h2 id="looping-through-files">Looping through files</h2>
<p>
Let's revisit our fruit gallery from before, but instead of manually specifying the list of fruits, we'll use
PHP's <a href="https://www.php.net/manual/en/function.glob.php"><code>glob()</code></a> function. It'll
produce an array of all the files in the <code>img/fruit/</code> directory, which we can then loop through
(using <code>foreach</code>) to display each image:
</p>
<?php code_block_from_file( '03-lists-and-loops/loop-through-files.php', 'php' ); ?>
<p>
Now if we add a new <code>.jpg</code> file into the <code>img/fruit/</code> directory, it will automatically be
added to the gallery.
</p>
<p class="tip">
What if there were both <code>.jpg</code> and <code>.webp</code> images in the directory? Can you work out how
to loop through both types of image using a single loop?
<a href="https://www.php.net/manual/en/function.array-merge.php"><code>array_merge()</code></a> might be useful.
What about if you want to keep the fruit in alphabetical order, regardless of their file extension?
Then you might want to use the <a href="https://www.php.net/manual/en/function.sort.php"><code>sort()</code></a> function.
<small>(<a href="https://php.danq.dev/demo-harness.php?file=public/appendix-samples/fruity-gallery-2.php">🏁 view solution</a>)</small>
</p>
<h2 id="selecting-from-an-array">Showing a random quote</h2>
<p>
PHP provides the <a href="https://www.php.net/manual/en/function.array-rand.php"><code>array_rand()</code></a> function
which selects a random key from an array. Let's use that to show a random quote to our visitors:
</p>
<?php code_block_from_file( '03-lists-and-loops/random-quote.php', 'php' ); ?>
<p class="tip">
Could you use this technique to show a random image, <em>and</em> apply a random CSS effect to it?
<a href="/demo-harness.php?file=public/appendix-samples/random-image-with-effect.php">🏁 view solution</a>
</p>
<?php
add_footer();
?>