Originally published on phpdesignpatterns.dev — part of the PHP design patterns course. View this lesson on the original site.

A discount calculator that started small

Here's the kind of code that triggered this chapter. A discount calculator for an online shop. It started with two cases. It now has six.

Before

<?php

final class DiscountCalculator
{
    public function calculate(string $customerType, int $totalInPence): int
    {
        if ($customerType === 'guest') {
            return 0;
        }

        if ($customerType === 'standard') {
            if ($totalInPence > 5000) {
                return (int) round($totalInPence * 0.05);
            }
            return 0;
        }

        if ($customerType === 'loyalty') {
            return (int) round($totalInPence * 0.10);
        }

        if ($customerType === 'loyalty_plus') {
            $discount = (int) round($totalInPence * 0.15);
            return min($discount, 2000);
        }

        if ($customerType === 'employee') {
            return (int) round($totalInPence * 0.40);
        }

        if ($customerType === 'partner') {
            $base = (int) round($totalInPence * 0.20);
            return $base + 500;
        }

        return 0;
    }
}

What we are looking at

Six customer types. Six rules. One method. Reading it requires you to hold all six rules in your head at once. Adding a seventh — say, student — means another if block and another silent assumption that the order of branches doesn't matter.

The next two lessons look at why that pain is worse than it appears, and then how Strategy splits this into something the team can actually live with.

From PHP design patterns — Strategy: replacing branching with swappable behaviour