ConcurrencyPHPverifiedVerified

Producer-Consumer Pattern in PHP

Decouple data production from data consumption using a shared buffer, allowing each side to operate at its own pace.

How to Implement the Producer-Consumer Pattern in PHP

1Step 1: Define the bounded queue using SplQueue

class BoundedQueue
{
    private \SplQueue $items;
    private int $size = 0;

    public function __construct(
        private readonly int $capacity,
    ) {
        $this->items = new \SplQueue();
    }

    public function enqueue(mixed $item): bool
    {
        if ($this->size >= $this->capacity) {
            return false; // Queue full
        }
        $this->items->enqueue($item);
        $this->size++;
        return true;
    }

    public function dequeue(): mixed
    {
        if ($this->items->isEmpty()) {
            return null;
        }
        $this->size--;
        return $this->items->dequeue();
    }

    public function isFull(): bool { return $this->size >= $this->capacity; }
    public function isEmpty(): bool { return $this->items->isEmpty(); }
    public function getSize(): int { return $this->size; }
}

2Step 2: Simulate producer and consumer using Fibers

function producer(BoundedQueue $queue, int $count): \Fiber
{
    return new \Fiber(function () use ($queue, $count): void {
        for ($i = 0; $i < $count; $i++) {
            while ($queue->isFull()) {
                \Fiber::suspend('queue_full');
            }
            $queue->enqueue($i);
            echo "Produced: {$i}\n";
            \Fiber::suspend('produced');
        }
    });
}

function consumer(BoundedQueue $queue, int $count): \Fiber
{
    return new \Fiber(function () use ($queue, $count): void {
        for ($i = 0; $i < $count; $i++) {
            while ($queue->isEmpty()) {
                \Fiber::suspend('queue_empty');
            }
            $item = $queue->dequeue();
            echo "Consumed: {$item}\n";
            \Fiber::suspend('consumed');
        }
    });
}

3Step 3: Coordinate fibers to simulate concurrency

$queue = new BoundedQueue(3);
$p = producer($queue, 5);
$c = consumer($queue, 5);

$p->start();
$c->start();

while (!$p->isTerminated() || !$c->isTerminated()) {
    if (!$p->isTerminated()) $p->resume();
    if (!$c->isTerminated()) $c->resume();
}

Producer-Consumer Pattern Architecture

hourglass_empty

Rendering diagram...

lightbulb

Producer-Consumer Pattern in the Real World

Think of a bakery where bakers (producers) place fresh loaves on a display shelf (the queue) and customers (consumers) pick them up at their leisure. The shelf decouples the baking schedule from customer arrival times — bakers keep baking even when no customer is present, and customers keep shopping even when bakers are on break.