PHP Kata: Fizz Buzz for not-so absolute beginners


Find out how you can gather additional knowledge from this simple kata. I will guide you through the process of refactoring of Fizz Buzz Kata in PHP

Foreword

In the previous article about Fizz Buzz Kata in PHP for absolute beginners I guided you through the simplest implementation of this Kata. This was because I wanted you to focus on basic PHP concepts like variables, conditions, and operators. In this article, I will show you how to refactor the code we developed previously. This way I will introduce you to new programming concepts. Buckle up seat belts - we are starting.

P.S. I assume you are already familiar with what we did last time.

Current state

Our solution, in the form we left it, looks like this:

<?php

$number = $argv[1];
$result = $number;

if ($number % 2 == 0) {
    $result = 'fizz';
}

if ($number % 3 == 0) {
    $result = 'buzz';
}

if ($number % 2 == 0 && $number % 3 == 0) {
    $result = 'fizzbuzz';
}

echo 'You said ' . $result . '!';

As you can see - we used 3 if statements. And in the last one, we do the same calculation as in the first and the second if. Asking the computer to do the same calculations twice is not polite in my opinion.

Today we will try to fix it - but how?

The idea behind

In the beginning, you need an idea :). As this article is for you to learn something - why not try the concept known from Linux file permissions. In Linux each file or folder can have such access rights:

  • r for reading,
  • w for writing,
  • x for executing. But it can also be mapped to numbers, where:
  • x = 1,
  • w = 2,
  • r = 4.

This way we can describe particular access rights combinations like this:

  • read only = 4,
  • read and write = 6,
  • read, write, and execute = 7,
  • read and execute = 5.

Each combination has its unique number. We can do the same trick with modulo calculations. Check this out:

  • number % 2 can have only two results: 0 or 1,
  • number % 3 can have only three results: 0, 1, or 2. This will give us such combinations and expected results:
  • 0, 0 -> fizzbuzz
  • 0, 1 -> fizz
  • 0, 2 -> fizz
  • 1, 0 -> buzz
  • 1, 1 -> number
  • 1, 2 -> number

We will go a little bit further and assign different weights for the results of modulo 2 and modulo 3. The weights we use will be as follow:

  • 1 for the result of modulo 2,
  • 2 for the result of modulo 3.

Having this defined we are able to generate such a table of truth:

Modulo 2 result Modulo 2 weight Modulo 2 final result Modulo 3 result Modulo 3 weight Modulo 3 final result Final result Expected output
0100200 + 0 = 0dividable by 2 and dividable by 3 -> fizzbuzz
0101220 + 2 = 2dividable by 2 and not dividable by 3 -> fizz
0102240 + 4 = 4dividable by 2 and not dividable by 3 -> fizz
1110201 + 0 = 1not dividable by 2 and dividable by 3 -> buzz
1111221 + 2 = 3not dividable by 2 and not dividable by 3 -> number
1112241 + 4 = 5not dividable by 2 and not dividable by 3 -> number

To sum this up, our tabel of truth will look like this:

  • 0 -> fizzbuzz
  • 1 -> buzz
  • 2 -> fizz
  • 3 -> number
  • 4 -> fizz
  • 5 -> number

What we can do with this? Today we will play with arrays.

Arrays in PHP

As you probably know - we have many types of variables. One of them is an array type. You can imagine it as a one-row table. This is a simplification - but I find it very appropriate right now. Your imaginary table can have as many cells as you want. But each cell has its name. You can use as names either numbers (like 0, 1, 2, 3, etc.), actual names (like alice, bob, john, etc.), or whatever you want (like warsaw, chicago, paris, etc.).

If you use numbers - we will call them indexes and the whole array will be called an indexed array. Usually, the first index in a PHP array is 0. You can define an array as follow:

$myArray = ['alice', 'bob'];

In the code above, we declared an array called $myArray. We assigned two elements to it. The first element has a value set to alice and the second one to bob. We can access them like this:

echo 'This is the first element value: ' . $myArray[0];
echo 'This is the second element value: ' . $myArray[1];

We can also change value:

$myArray[1] = 'New value for the second element';
$myArray[0] = 15;

The above code replaced the initial values of our array with 15 for the first element and New value for the second element for the second one.

You can also append value at the end of an array:

$myArray[] = 'This is value for new element that will be the third';

This is how we can work with indexed arrays. And what about those with named cells?

Associative arrays in PHP

The second type of PHP array is an associative array. This type of array use names as cells indexes. And those names are called keys. So an associative array is about keys and their corresponding values. If you look carefully, you may find that there is no such difference between both array types. And yes, in some way it is true. This is why you can use associative arrays almost same as indexed ones:

$myAssociativeArray = ['name' => 'Adam', 'surname' => 'Wojciechowski', 'lovedLanguage' => 'PHP'];

We just created an associative array called $myAssociativeArray. We assigned three elements to it. But there is no first, second, or third one. There are three elements, one associated with the key named name, one associated with the key named surname, and finally one associated with the key named lovedLanguage. Take a look at this => - it is called an arrow operator (I wonder why ;P). It is responsible for assigning values to keys. Now see how you can use it:

echo 'My name is: ' . $myAssociativeArray['name'];
echo 'And I love to code in: ' . $myArray['lovedLanguage'];

And this is how you can replace value od add new one:

$myAssociativeArray['lovedLanguage'] => 'Perl';
$myAssociativeArray['justKidding'] => 'PHP is my loved language';

Few side notes:

  1. Keys or indexes in arrays are unique. You can not have multiple keys with the same name.
  2. You can mix up both types of arrays, e.g. like this:
$mixedArray = ['alice', 4 => 'bob', 'name' => 'Adam'];

Ok. So these are the absolute basics of arrays in PHP. Let's try to utilize them in our Fizz Buzz Kata.

First step in refactorisation

Our first step will be to check if our current solution works. Execute it for cases we defined in the previous article:

  • 1 -> You said 1!
  • 2 -> You said fizz!
  • 3 -> You said buzz!
  • 6 -> You said fizzbuzz!

Is everything ok? Yes - we can start with changes. Add $resultMap between $number and $result like this:

<?php

$number = $argv[1];
$resultMap = ['fizzbuz', 'buzz', 'fizz', $number, 'fizz', $number];
$result = $number;

What just happened? We declared our result map in a form of an array. Now we need only to calculate the index number.

Calculate index number

Our algorithm for calculating index number is almost trivial: index = (number modulo 2) * weight for 2 + (number modulo 3) * weight for 3

Add this calculation just below the $resultMap:

<?php

$number = $argv[1];
$resultMap = ['fizzbuz', 'buzz', 'fizz', $number, 'fizz', $number];
$index = ($number % 2) + (($number % 3) * 2);
$result = $number;

And now we are ready for final clean up:

<?php

$number = $argv[1];
$resultMap = ['fizzbuz', 'buzz', 'fizz', $number, 'fizz', $number];
$index = ($number % 2) + (($number % 3) * 2);

echo 'You said ' . $resultMap[$index] . '!';

That's it!

Wrap up

With this refactorisation we simplified our code. We replaced 3 conditions with one simple arithmetic calculation. We eliminated code duplication as well.

As a bonus we can also optimize last line:

<?php

$number = $argv[1];
$resultMap = ['fizzbuz', 'buzz', 'fizz', $number, 'fizz', $number];
$index = ($number % 2) + (($number % 3) * 2);

echo "You said {$resultMap[$index]}!";

Keep calm and code with WeBee!

Not enough?


Would you like me to build and conduct training tailored to your needs? I'm waiting for your call or message.

address icon

WeBee.Online Adam Wojciechowski
ul. Władysława Łokietka 5/2
70-256 Szczecin, Poland