DEV Community

Cover image for Refactoring If-Else Hell into a Strategy Pattern in PHP ⚙️
CodeCraft Diary
CodeCraft Diary

Posted on • Originally published at codecraftdiary.com

Refactoring If-Else Hell into a Strategy Pattern in PHP ⚙️

Hey there! Today I want to share a common problem I’ve faced many times in PHP projects: a method full of if/else if statements that handles different types of orders. You know the type—huge, unreadable, and almost impossible to extend without breaking something. 😅

In this article, I’ll show you how to refactor such if-else hell into something much cleaner using the Strategy Pattern. By the end, you’ll see how flexible, testable, and maintainable your code can become.

1️⃣ The Problem: Long If-Else Chains

Let’s imagine we have a simple OrderProcessor class:

class OrderProcessor {
    public function process(Order $order) {
        if ($order->type === 'digital') {
            echo "Processing digital order\n";
            // some digital-specific logic
        } elseif ($order->type === 'physical') {
            echo "Processing physical order\n";
            // physical-specific logic
        } elseif ($order->type === 'subscription') {
            echo "Processing subscription order\n";
            // subscription-specific logic
        } else {
            throw new Exception("Unknown order type");
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

At first glance, it works… but as soon as you add more types or more complex rules, this method grows quickly.

Problems with this approach:

  • Adding a new order type requires editing this method → violates Open/Closed Principle.
  • Hard to test individual behaviors without setting up multiple scenarios.
  • Readability decreases as the logic grows.

This is the classic if-else hell—something we want to avoid.

2️⃣ Diagnosing the Problem

Before refactoring, it’s good to understand the main issues:

  • Duplicated logic across conditions.
  • High coupling: OrderProcessor knows about every type.
  • Poor testability: you can’t isolate behavior easily.

So what do we want? We want a solution where:

  • Each order type handles its own logic.
  • Adding a new type does not break existing code.
  • The code is easy to test and extend.

Enter the Strategy Pattern. 🛠️

3️⃣ Refactoring Step by Step

Step 1: Define a Strategy Interface

First, we create an interface that all order strategies will implement:

interface OrderStrategy {
    public function process(Order $order): void;
}

Enter fullscreen mode Exit fullscreen mode

This way, every strategy guarantees it can process an Order.

Step 2: Implement Concrete Strategies

Next, we create a class for each order type:

class DigitalOrderStrategy implements OrderStrategy {
    public function process(Order $order): void {
        echo "Processing digital order\n";
        // digital-specific logic here
    }
}

class PhysicalOrderStrategy implements OrderStrategy {
    public function process(Order $order): void {
        echo "Processing physical order\n";
        // physical-specific logic here
    }
}

class SubscriptionOrderStrategy implements OrderStrategy {
    public function process(Order $order): void {
        echo "Processing subscription order\n";
        // subscription-specific logic here
    }
}

Enter fullscreen mode Exit fullscreen mode

Notice how each class o*nly handles its own behavior*. Much cleaner, right?

Step 3: Create a Context (OrderProcessor)

Now, we modify OrderProcessor to use these strategies:

class OrderProcessor {
    private array $strategies;

    public function __construct(array $strategies) {
        $this->strategies = $strategies;
    }

    public function process(Order $order) {
        if (!isset($this->strategies[$order->type])) {
            throw new Exception("Unknown order type");
        }

        $this->strategies[$order->type]->process($order);
    }
}

Enter fullscreen mode Exit fullscreen mode

We pass an array of strategies to the processor. The processor doesn’t care how each strategy works, only that it can process the order.

Step 4: Using the Refactored Code

$processor = new OrderProcessor([
    'digital' => new DigitalOrderStrategy(),
    'physical' => new PhysicalOrderStrategy(),
    'subscription' => new SubscriptionOrderStrategy(),
]);

$order = new Order('digital');
$processor->process($order);

Enter fullscreen mode Exit fullscreen mode

See how easy it is to add a new type? Just create a new class implementing OrderStrategy and add it to the array. No need to touch existing logic.

4️⃣ Testing Strategies

One of the biggest advantages: testing becomes simple. Each strategy can be tested in isolation:

class DigitalOrderStrategyTest extends TestCase {
    public function testProcess() {
        $order = new Order('digital');
        $strategy = new DigitalOrderStrategy();

        $this->expectOutputString("Processing digital order\n");
        $strategy->process($order);
    }
}

Enter fullscreen mode Exit fullscreen mode

Repeat for other strategies!

5️⃣ Benefits of Using Strategy Pattern

  • Open/Closed Principle: Adding new behaviors doesn’t break existing code.
  • Single Responsibility: Each class has one reason to change.
  • Testability: Strategies are isolated and easy to test.
  • Extensibility: Adding a new order type is trivial.

6️⃣ Quick Tips & Best Practices

  • Use Factory if you have many strategies: Helps with dependency injection.
  • Keep strategies small: Each class should do one thing.
  • Don’t overuse: If you only have 2-3 cases, sometimes a simple if/else is fine. Strategy shines with growing variability.
  • Document the intent: Strategy is about interchangeable behavior, not just splitting code.

7️⃣ Conclusion

Refactoring if-else hell into a Strategy Pattern in PHP is a straightforward way to clean up messy code, make it extensible, and improve testability.

  • Identify the long if-else chains.
  • Extract each behavior into a separate class implementing a common interface.
  • Use a context class (or processor) to delegate work.
  • Enjoy your cleaner, flexible code.

Give it a try on your next messy class—you’ll thank yourself later.

Top comments (0)