From Procedural to Object Oriented Programming - Part 1

This will be a two part post about transitioning from procedural to object oriented programming paradigm.

In this post we will take a step by step look at a basic calculator script in a procedural way and in the next post we will take a look how we can transfer this to object oriented paradigm and implement some basic error handling. You can find this script at my github repository.

Objective

Create a basic CLI Calculator script which handles adding, subtracting, multiplying and division.

Start of our script

Create a php file named: procedural-calculator.php. With the following contents:

<?php declare(strict_types=1);

if (php_sapi_name() !== 'cli') {
    die('This script can be called only from the command line.' . PHP_EOL);
}

if (count($argv) <= 1) {
    die('You need to provide an operation!' . PHP_EOL);
}

Since we are creating a CLI (Command line interface) script, we want to ensure that nobody can call it from a web server and that is what the first if clause is doing, php_sapi_name() function returns the interface that is being called from.

The second check if (count($argv) <= 1) is accepting a variable of type array that is never defined by ourselves, this variable is automatically injected in to our script when it is being called from CLI.

The variable $argv holds all the arguments that have been used in the script call. For example if we call our script like this: php procedural-calculator.php arg1, $argv variable will be filled with two values. First element ($argv[0]) will always be the name of the script in our case that would be: procedural-calculator.php and the second elements ($argv[1]) value would be arg1.

Find operator function

function findOperator(string $input, array $allowedOperators): ?string {
    $result = null;

    foreach ($allowedOperators as $operator) {
        if (strpos($input, $operator)) {
            $result = $operator;
            break;
        }
    }

    return $result;
}

This function accepts two arguments, the first one is $input of type string (eg.: 5*10) which is the expression that the user provides. Second argument is the $allowedOperators of type array which contains operators that we accept. If a valid operator is provided it will return a string of that operator, otherwise it will return null which we will handle afterwards. Our implementation expects the operands and the operations to be provided together (eg.: 12/4), but you can adjust that and accept arguments that are called seperately, like so: php procedural-calculator.php 5 * 5.

Define separate functions for calculations

function add(int $a, int $b): int {
    return $a + $b;
}

function subtract(int $a, int $b): int {
    return $a - $b;
}

function multiply(int $a, int $b): int {
    return $a * $b;
}

function divide(int $a, int $b): float {
    return $a / $b;
}

This is a straight forward implementation of calculating a result of two values. Each function accepts two arguments which are than returned to the caller.

Find operator and obtain the $a and $b operands

$operation = $argv[1];

$allowedOperators = [
    '+',
    '-',
    '*',
    '/'
];

$operator = findOperator($operation, $allowedOperators);

if (null === $operator) {
    die('Unrecognized operand provided!' . PHP_EOL);
}

[$a, $b] = explode($operator, $operation);

if (!is_numeric($a) || !is_numeric($b)) {
    die('Provided arguments are not of type integer.' . PHP_EOL);
}

First we saved $argv[1] variable to the $operation variable since we will use it later again and it is more clear to read and understand. After that we define $allowedOperators array that we will in the call for the findOperator function to check if the user provided operator is correct. If the return value is null we just terminate the script with die() function, because we cannot continue with execution, next we check whether the provided operands are numeric type, if not we terminate the script again.

Putting it all together

Now we just need to call the correct calculation function based on the provided operator, and we print our result at the end.

switch($operator) {
    case '+':
        $result = add((int)$a, (int)$b);
        break;
    case '-':
        $result = subtract((int)$a, (int)$b);
        break;
    case '*':
        $result = multiply((int)$a, (int)$b);
        break;
    case '/':
        $result = divide((int)$a, (int)$b);
        break;
}

printf('Result is: %s' . PHP_EOL, $result);

Now we can call this script like so: php procedural-calculator.php 5*5. The same goes for the other operations.

What's next

This was an introduction to the procedural paradigm, which we will improve in the next post when we will modify our code to be Object Oriented.