3.9. State

3.9.1. Purpose

Encapsulate varying behavior for the same routine based on an object’s state. This can be a cleaner way for an object to change its behavior at runtime without resorting to large monolithic conditional statements.

3.9.2. UML Diagram

Alt State UML Diagram

3.9.3. Code

You can also find these code on GitHub

OrderRepository.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php

namespace DesignPatterns\Behavioral\State;

class OrderRepository
{
    /**
     * @var array
     */
    private static $orders = [
        1 => ['status' => 'created'],
        2 => ['status' => 'shipping'],
        3 => ['status' => 'completed'],
    ];

    public static function findById(int $id): Order
    {
        if (!isset(self::$orders[$id])) {
            throw new \InvalidArgumentException(sprintf('Order with id %d does not exist', $id));
        }

        $order = self::$orders[$id];

        switch ($order['status']) {
            case 'created':
                return new CreateOrder($order);
            case 'shipping':
                return new ShippingOrder($order);
            default:
                throw new \InvalidArgumentException('Invalid order status given');
                break;
        }
    }
}

Order.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<?php

namespace DesignPatterns\Behavioral\State;

interface Order
{
    /**
     * @return mixed
     */
    public function shipOrder();

    /**
     * @return mixed
     */
    public function completeOrder();

    public function getStatus(): string;
}

ShippingOrder.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php

namespace DesignPatterns\Behavioral\State;

class ShippingOrder implements Order
{
    /**
     * @var array
     */
    private $details;

    /**
     * @param array $details
     */
    public function __construct(array $details)
    {
        $this->details = $details;
    }

    public function shipOrder()
    {
        throw new \Exception('Can not ship the order which status is shipping!');
    }

    public function completeOrder()
    {
        $this->details['status'] = 'completed';
        $this->details['updatedTime'] = time();
    }

    public function getStatus(): string
    {
        return $this->details['status'];
    }
}

CreateOrder.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php

namespace DesignPatterns\Behavioral\State;

class CreateOrder implements Order
{
    /**
     * @var array
     */
    private $details;

    /**
     * @param array $details
     */
    public function __construct(array $details)
    {
        $this->details = $details;
    }

    public function shipOrder()
    {
        $this->details['status'] = 'shipping';
        $this->details['updatedTime'] = time();
    }

    public function completeOrder()
    {
        throw new \Exception('Can not complete the order which status is created');
    }

    public function getStatus(): string
    {
        return $this->details['status'];
    }
}

3.9.4. Test