Exercise: Palindromes

Exercise 8 Easy

Prerequisites for the exercise

  1. PHP Functions
  2. PHP Control Flow
  3. All previous chapters

Objective

Create a function to test whether a given word is a palindrome or not.

Description

A palindrome is a word that reads the same forwards and backwards.

For example, 'ada' is a palindrome. If you read it forwards, it's 'ada'; and similarly, if you read it backwards, it's still 'ada'. Since it's the same in both directions, it's a palindrome.

Now, consider the word 'bulb'. Forwards, it's read as 'bulb'. But backwards, it's read as 'blub'. Since both these directions yield different words, 'bulb' is not a palindrome.

By this means, every single letter is a palindrome as well. 'a' is a palindrome, 'b' is a palindrome, and so on and so forth.

In this exercise, you have to create a program that asks the user to enter a word, and then outputs backs 'Yes' if it is a palindrome, or otherwise 'No'.

The input prompt asking for the word shall be as follows:

Enter a word: <word>

where <word> denotes the word entered by the user to be run against a palindrome check.

Shown below are two examples:

Enter a word: ada Yes
Enter a word: Ada No
Enter a word: bulb No

Note that you must create a function is_palindrome() for this exercise.

The function should have the following signature:

<?php

function is_palindrome($word) {
   // Code here.
}

It must return true is the given $word is a palindrome, or else false.

Moreover, as can be seen in the second example above, is_palindrome() must operate case-sensitively i.e. 'Ada' should not be considered as a palindrome because the beginning and ending characters aren't of the same case.

Hints

Hint 1

Use a for loop to iterate as far as almost half the length of the string $word.

View Solution

New file

Inside the directory you created for this course on PHP, create a new folder called Exercise-8-Palindromes and put the .php solution files for this exercise within it.

Solution

Before even starting to write a single piece of code, let's try to solve this problem by hand in discrete steps.

So how can we determine whether a word is a palindrome or not?

For a string to be a palindrome, it has to have the same characters in both directions. That is, the first and last characters must be the same; the second and second-last characters must be the same; and so on.

Let's consider the word 'ada'.

Clearly, the first and last characters are the same. Moving on to the second character, it's also the same as the second-last character. In fact, the second character is the second-last character. Moving further ahead, the third character is the same as the third-last character. Wait...

Haven't we already compared the first and last characters before?

Well, sure we have. This seems like redundant work which must be prevented.

Any guesses on how to prevent ourselves from performing the same comparison again.

Well, let's see.

Beyond the mid-point of the word, we don't need to do any further comparisons since the entire sequence of characters to the right has already been gone over in previous comparisons.

In fact, if you think about it carefully, we don't even need to perform the comparison over the middle character (if there is one). This is because the comparison of that characters turns out to be against itself, and would likewise trivially yield a match.

Hence, we just need to iterate right upto (and excluding) the middle character of a given string, comparing it with corresponding characters from the right side to determine if the string is a palindrome.

Let's now consider the word 'bulb'.

The first and last characters are the same. However, the second and second-last characters don't match one another. Hence, the string is not a palindrome.

Let's consider another word 'dioid'.

The first and last characters are the same. So is the case with the second and second-last characters. The third character is the middle character and hence we don't need to perform any comparison for it. In the end, we know that 'dioid' is a palindrome.

Alright, now that we have the full plan for a palindrome check algorithm in hand, it's time to convert it to PHP code.

As instructed in the exercise, we ought to create an is_palindrome() function as shown below:

<?php

function is_palindrome($word) {
   // Code here.
}

Step one is to lay out a for loop in the function. This is to iterate over the given string $word and perform the comparisons over corresponding characters.

This is accomplished below:

<?php

function is_palindrome($word) {
   for ($i = 0; $i < strlen($word) / 2; $i++) {
      // Code here.
   }
}

Since, we need to iterate upto the middle index (excluding it), we use $i < strlen($word) / 2. Inside the loop, we compare the $ith character of $word with the corresponding characters from the right of the string.

To determine the exact index here of the other character, we subtract $i from strlen($word) and subtract 1.

For instance, if the string is 'ada' and $i = 0, this index would be 3 - 0 - 1 as strlen($word) would be 3.

If the comparison results in a mismatch, we immediately exit the function by returning false, since there is no point in checking further.

However, if this conditional's body never executes, that means that no mismatches were found and hence the string is a palindrome. Likewise, outside the loop in the next statement, we return true.

This leads to the following code:

<?php

function is_palindrome($word) {
   for ($i = 0; $i < strlen($word) / 2; $i++) {
      if ($word[$i] !== $word[strlen($word) - $i - 1]) {
         return false;
      }
   }
   return true;
}

This is only one part of our program. We still haven't laid out the code for the input prompt and the desired output message.

Let's do that next:

<?php

function is_palindrome($word) {
   for ($i = 0; $i < strlen($word) / 2; $i++) {
      if ($word[$i] !== $word[strlen($word) - $i - 1]) {
         return false;
      }
   }
   return true;
}


echo 'Enter a word: ';
$word = rtrim(fgets(STDIN));

if (is_palindrome($word)) {
   echo 'Yes';
}
else {
   echo 'No';
}

This completes our exercise.

Improving the function

If you notice one thing in the definition of is_palindrome() above, the expression strlen($word) is being repeated twice.

This is not good.

Instead, we should create a variable to cache the value of strlen($word) and then use that variable in place of strlen($word) to prevent the repetition.

Let's call the variable $len and define it right above the for loop.

Here's the complete, and more efficient, code:

<?php

function is_palindrome($word) {
   $len = strlen($word);

   for ($i = 0; $i < $len / 2; $i++) {
      if ($word[$i] !== $word[$len - $i - 1]) {
         return false;
      }
   }

   return true;
}

Great.

In these early days of coding, preventing this repetition of expressions would be a governing factor in determining what variables to create in a program.

That is, you'll notice the repetitive expressions and replace each of them with a variable holding the value of that very expression.

But as you continue on this long journey of programming, your mind will naturally become more capable and fond of such concerns and transition from thinking like 'here we are repeating stuff, hence we should use a variable' to 'here we will be repeating stuff, hence let's create a variable beforehand.'

In other words, you'll be able to foresee many, if not all, of the variables required in a piece of code and define them even before you begin to write the actual code.

Programming in a beautiful way is more than just a science — it is an art.

"I created Codeguage to save you from falling into the same learning conundrums that I fell into."

— Bilal Adnan, Founder of Codeguage