Lesson Weekend

It's time for our programs to start to think for themselves. We're going to teach them to make decisions by branching.

Say that we are creating a website to rate local bars, but we don't want minors trying to rate bars since they aren't allowed to drink. We will need a function that checks a user's age and returns "You can drink!" if they are over 21, but returns "No drinks for you!" if they are under 21.

Our function's only input is the user's age. So our declaration looks like this (follow along in a text file and we can paste it into the PHP shell after we fill it in):

function checkAge($user_age) 
{

}

Now we need to know if $user_age is greater than or equal to 21. To do this, we are going to use a tool called an if statement:

function checkAge($user_age)
{
    if ($user_age >= 21) {
        return "You can drink!";
    }
}

When the PHP interpreter sees the keyword if, it expects to see a set of parenthesis next to it. Inside the parenthesis should be a statement which is either true or false. This kind of statement is called a condition. In our condition, we are using the >= symbol, which means "greater-than-or-equal-to".

Let's work through a couple examples of the above condition. If $user_age is equal to 25, $user_age >= 21 becomes 25 >= 21, which evaluates to true. In this case, the code in the curly brackets under the condition is run.

But if $user_age is equal to 16, $user_age >= 21 becomes 16 >= 21, which evaluates to false. In this case, the code in the curly brackets is skipped.

The >= symbol is called a comparison operator because it allows you to compare two values - one on either side of the operator symbol. These operators are used in conditions and they always evaluate to true or false. Here are a few other comparison operators:

  1. == means "equal-to". 5 == 5 or "cat" == "cat" evaluate to true, but 3 == 5 or "cat" == "dog" evaluate to false.
  2. != means "not-equal-to". It is the opposite of ==, so "cat" != "dog" evaluates to true, but 5 != 5 evaluates to false, because saying that 5 is not equal to 5 is not true.
  3. > means "greater-than (and not equal to)". 3 > 4 evaluates to false; 3 > 3 also evaluates to false, because 3 is equal to 3 and not greater; and 3 > 2 evaluates to true.
  4. >= is the same as >, except it evaluates to true if the two sides are equal. 3 >= 3 evaluates to true, and so does 3 >= 2.
  5. < is the opposite of >. It means "less-than (and not equal to)". 3 < 5 evaluates to true. 3 < 3 evaluates to false because they are equal.
  6. <= is the opposite of >=. It means "less-than-or-equal-to". 3 <= 3 evaluates to true because 3 is equal to 3. 3 <= 1 evaluates to false, but 3 <= 5 evaluates to true.

Back in our bar rating website, let's return a different sentence if the condition is false (the user is under 21):

function checkAge($user_age)
{
    if ($user_age >= 21) {
        return "You can drink!";
    }
    else {
        return "No drinks for you!";
    }
}

Here, just like before, when the condition in parentheses evaluates to true, the code in the first set of curly brackets is run. But when the condition evaluates to false, the code in the second set of curly brackets, after the else keyword`, is run.

There's no need for a condition in parenthesis after the else keyword, because the code in its curly brackets is run automatically if the first condition next to the if statement is false.

Generally, your code is executed from top to bottom, like a car driving straight down the road. When your car encounters an if statement, it is like encountering a fork in the road. You can't take both paths - if the condition is true, the if code runs, otherwise the else code runs.

Let's try out our function. Start the PHP shell by running the command php -a in your terminal, and then paste in the function checkAge. Now, type these commands:

> echo checkAge(24);
You can drink!
> echo checkAge(19);
No drinks for you!
> echo checkAge(21);
You can drink!

Our function returns one message for input numbers that are 21 or over, and a different message for input numbers not over 21. What if we want to print out a special third message if the user's age is equal to 21? Let's print out "You must be really excited about drinking!" if the user is 21. To do this we will use a new keyword in our function called elseif.

function checkAge($user_age)
{
    if ($user_age > 21) {
        return "You can drink!";
    }
    elseif ($user_age == 21) {
        return "You must be really excited about drinking!";
    }
    else {
        return "No drinks for you!";
    }
}

elseif is just like an alternate if. It also has a condition to be checked in parenthesis next to it, and if that condition is true then the code in curly brackets following it is run. But elseif's condition is only checked when the if condition has already been found to be false.

In real life, you use this idea of if, elseif and else all the time. Say you're going to the beach with your friends over the weekend. You all decide that the easiest way to get there would be to drive, but only your friend Lindsey has a car. So, if Lindsey is free, you can all drive with her. But, she never picks up her phone. So, you all decide that as an alternate plan you will take the bus - but only if Lindsey is busy. Then one of your friends remembers that this is a holiday weekend, so the bus might not be running. You roll your eyes at your friend and say "Fine, if we can't find Lindsey, and the buses aren't running, we can all just go to my house and watch movies." That is an if statement! Let's re-interpret this discussion in code:

if ($lindsey == "available to drive") {           // if Lindsey can drive...
    drive_to_beach($friends);                      // call the function to drive to the beach.
} 
elseif ($buses_are_running == true) {       // if Lindsey can't drive and the buses are running...
    bus_to_beach($friends);                       // take the bus to the beach.
}
else {                                                         // if all the other options fail...
    watch_movies($friends);                       // watch movies instead.
}

The double equals sign == is easy to mix up with the single equals sign =. Remember that the single equals sign (=) is used to assign a value to a variable. The double equals (==) is used in conditions to check if the values on its left and right sides are equal.

When you are writing an if statement, you can have as many elseifs in it as you like, but you can only have one if and one else. if must be the first statement, and else must be the last statement.

Let's do another example. We'll make a website where the user tries to guess a number. We'll have PHP pick a random number between 1 and 20, and we'll have the user enter a number into a form for their guess. We'll keep it simple by only giving them one guess, and then PHP will tell them if the guess is too high, too low or correct.

Let's start with the PHP. Create a file in your document root called "guess_my_number.php" and type this into it.

<?php
    $guess = 5; // in a moment, we'll switch this to be from user input
    $favorite_number = 10; // we'll also switch this to be random
    $message = checkGuess($guess, $favorite_number);

    function checkGuess($guessed_number, $winning_number)
    {
        // code will go here
    }
?>

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
    <title>Guess My Number</title>
</head>
<body>
    <div class="container">
        <h1><?php echo $message; ?></h1>
    </div>
</body>
</html>

Here, we've temporarily hard-coded test values for $guess and $favorite_number. This way we can write the logic to check the guessed number against our favorite number without complicating things by using a form or a random number.

Since we are setting $guess = 5 and $favorite_number = 10, we know that if we write our function correctly, it should find that $guess is too low. So let's fill in that function with an if statement.

function checkGuess($guessed_number, $winning_number)
{
    if ($guessed_number == $winning_number) {
        return "Congrats! You guessed it!";
    }
    elseif ($guessed_number < $winning_number) {
        return "Too low! Sorry, you lose!";
    }
    else {
        return "Too high! Sorry, you lose!";
    }
}

Now if we go to http://localhost:8000/guess_my_number.php then it should show the text "Too low! Sorry, you lose!". Next, try changing the value of $guess to 14. Refresh the page and this time it should show "Too high! Sorry, you lose!". Now try setting $guess equal to 10. Refresh the page and it should read "Congrats! You guessed it!".

Now that our function is working, we can get rid of the test values. So, instead of setting $guess ourselves, let's use a form. Inside of guess_my_number.php, replace this line:

$guess = 5;

with:

$guess = $_GET["user_guess"];

Now we need a form to call this PHP file, and it should have one input field with the type attribute set to "number" and the name attribute set to "user_guess". Put the file in your document root and call it guess_my_number_form.html.

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
    <title>Guess a number</title>
</head>
<body>
    <div class="container">
        <h1>Guess my favorite number!</h1>
        <form action="guess_my_number.php">
            <div class="form-group">
                <label for="user_guess">Pick a number between 1 and 20</label>
                <input id="user_guess" name="user_guess" class="form-control" type="number">
            </div>
            <button type="submit" class="btn-success">Go!</button>
        </form>
    </div>
</body>
</html>

We still have $favorite_number set to 10, so now we should run the same tests as we did when we were manually setting the value of $guess, but this time use the form. Make sure the correct text appears on the screen when you enter a number that's less than 10, a number that's more than 10, and finally 10 itself.

If all of that is working, it is time for the last step. We have to make PHP pick a number for us so that the winning number isn't always 10. To do that, we use a built-in function called rand (which stands for "random"). It takes two arguments - a minimum value and a maximum value - and it returns a random number between those two values. So, in guess_my_number.php, replace this line:

$favorite_number = 10;

with this one:

$favorite_number = rand(1, 20);

Now our little game should work! The minimum value for the winning number is 1 and the maximum is 20. Let's make sure that rand is doing what we expect by printing the answer as well as the guess on the ending page. So, here is the final guess_my_number.php file.

<?php 
    $guess = $_GET["user_guess"];
    $favorite_number = rand(1, 20);
    $message = checkGuess($guess, $favorite_number);

    function checkGuess($guessed_number, $winning_number)
    {
        if ($guessed_number == $winning_number) {
            return "Congrats! You guessed it!";
        }
        elseif ($guessed_number < $winning_number) {
            return "Too low! Sorry, you lose!";
        }
        else {
            return "Too high! Sorry, you lose!";
        }
    }
?>

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
    <title>Guess My Number</title>
</head>
<body>
    <div class="container">
        <h1><?php echo $message; ?></h1>
        <h3><?php echo "You guessed: " . $guess; ?> </h3>
        <h3><?php echo "The right answer was: " . $favorite_number; ?> </h3>
    </div>
</body>
</html>

Yay! You made a little number game.

Lastly, a few important stylistic notes. They will make your code neater and easier to debug. Also, if we all follow these conventions then it's easier to share code in each other's projects without having to get used to a whole new style.

if statements are written with the first curly bracket on the same line as the if keyword. It's the same thing with the curly brackets after the elseif and else keywords.

if ( $condition == true ) {

} elseif ( $another_condition == true ) {

} else {

}

However, functions have their first curly bracket on the line after the keyword function. This makes it easy to scan your code and see where the functions are and where the if statements are.

function nameOfFunction($argument1, $argument2) 
{

}

Two other notes on spacing: You should also put a single space on each side of the outside of the parenthesis after the if and elseif keywords. The else keyword doesn't use parenthesis, so just put a space before its opening curly bracket. Also, be sure to indent your code inside of the curly brackets, the same way you do with code inside of a function's curly brackets - 4 spaces. No tabs.

Don't do this:

if(condition){
// this isn't indented
}elseif(condition){
// it's so hard to read!
}else{
// where do things start and end?
}

Instead, do this:

if (condition) {  // much cleaner!
    // this is indented with 4 spaces
} elseif (condition) {
    // it's easy to read!
} else {
    // yup, 4 spaces here too.
}