Backend Development

Understanding the Pool Design Pattern in PHP with a Real-World Example

Understanding the Pool Design Pattern in PHP with a Real-World Example

When building applications, we often create and destroy objects repeatedly. In many cases, this is perfectly fine because object creation is inexpensive. However, some objects are expensive to create because they require external resources. This is where the Pool Design Pattern for.

 

 

Some objects are expensive to create because they require external resources such as:

  • Database Connections
  • Network Sockets
  • File Handles
  • API Clients
  • Browser Instances
  • Threads.

Creating these objects over and over again can negatively affect performance and waste system resources.

This is where the Pool Design Pattern comes into play.

 

 

What Is the Pool Design Pattern?

The Pool Pattern (also known as the Object Pool Pattern) is a creational design pattern that maintains a collection of reusable objects. Instead of creating a new object every time one is needed, the application:

  1. Requests an object from the pool.
  2. Uses the object.
  3. Returns it back to the pool when finished.

 

The object can then be reused by another part of the application.

Think of it like a car rental service:

  • The company owns a pool of cars.
  • Customers borrows a car.
  • After using it, they return it.
  • The same car is rented to another customer.

The cars are not destroyed and recreated after every customer.

 

When should you use the Pool Pattern?

The Pool Pattern is useful when:

  • Object creation is expensive.
  • The application frequently creates and destroys objects.
  • The object represents a limited resource.
  • You want to control the number of active instances.

 

Structure of the Pattern

The Pool Pattern usually consists of three components:

  1. The Reusable Object

The object you want to reuse:

class DatabaseConnection
{
    public function query(string $sql): array
    {
        echo "Executing: {$sql}\n";

        return [];
    }
}

2. The Pool Manager

Responsible for:

  • Creating objects.
  • Storing available objects
  • Lending objects
  • Receiving objects back

3. The client

The code that borrows objects from the Pool.

 

Implementing an Object Pool in PHP

Step 1: Create the Resource

class DatabaseConnection
{
    private PDO $pdo;

    public function __construct(
        string $dsn,
        string $username,
        string $password
    ) {
        $this->pdo = new PDO(
            $dsn,
            $username,
            $password
        );
    }

    public function getPdo(): PDO
    {
        return $this->pdo;
    }
}

Step 2: Create the Pool

class ConnectionPool
{
    private array $available = [];
    private array $used = [];

    public function __construct(
        private string $dsn,
        private string $username,
        private string $password,
        private int $maxConnections = 5
    ) {
    }

    public function acquire(): DatabaseConnection
    {
        if (!empty($this->available)) {
            $connection = array_pop($this->available);

            $this->used[spl_object_id($connection)] = $connection;

            return $connection;
        }

        if (count($this->used) < $this->maxConnections) {
            $connection = new DatabaseConnection(
                $this->dsn,
                $this->username,
                $this->password
            );

            $this->used[spl_object_id($connection)] = $connection;

            return $connection;
        }

        throw new RuntimeException(
            'No available connections.'
        );
    }

    public function release(
        DatabaseConnection $connection
    ): void {
        $id = spl_object_id($connection);

        if (isset($this->used[$id])) {
            unset($this->used[$id]);
            $this->available[$id] = $connection;
        }
    }
}

In this code the Pool class manages the available and used connections, this is a simplified version, but in real world project this class contains more logic than this. 

The two methods acquire() and release() handles creating a connection object and releasing the connection respectively.

To do that the acquire() method checks to see if there is available connections in the $available property, and if true it moves that to the $used property using spl_object_id() to generate unique id from the instance as an array key. If there is not any available connections if creates a new one.

The release() method do the opposite which free the $used connection and move it back to the $available resources.

 

Step 3: Use the Pool

$pool = new ConnectionPool(
    'mysql:host=localhost;dbname=shop',
    'root',
    'secret'
);

$conn = $pool->acquire();

$conn->getPdo()->query(
    'SELECT * FROM products'
);

$pool->release($conn);

The connection is returned to the pool instead of being destroyed.

 

Advantages of the Pool Pattern

  • Better Performance: Avoids repeated object creation.
  • Reduced memory Usage: Objects are reused instead of constantly allocated.
  • Controls Resource Consumption: Limits the number of expensive resources.
  • Improves scalability: Applications can handle more requests efficiently.

 

However note that the Pool pattern have dome disadvantages.

Disadvantages of the Pool Pattern

  • Added Complexity The code becomes more difficult to maintain.
  • Risk of Resource Leaks If an object is not returned to the pool, it becomes unavailable.
  • Synchronization Issues Multi-threaded applications require thread-safe pools.
  • Unnecessary for Lightweight Objects Pooling simple objects may actually reduce performance.

 

What about the Service Locator Pattern and Does it similar to the Pool Pattern?

At first glance, Object Pool and Service Locator all seem to “manage objects,” but they solve completely different problems.

Object Pool

Purpose:

Reuse expensive objects instead of creating new ones.

An object pool keeps two collections:

  • Available objects
  • Objects currently in use

When a client needs an object, it borrows one from the pool. Once finished, it returns the object to the pool to be reused.

$connection = $pool->acquire(); 

// Use the connection... 

$pool->release($connection);

The important point is that the same object instance may be reused many times.

 

Service Locator

Purpose:

A Service Locator acts as a centralized registry that knows how to find services.

$mailer = $locator->get(Mailer::class);

$logger = $locator->get(Logger::class);

The client simply asks for a service without knowing how it is created.

Unlike an Object Pool:

  • Services are usually not borrowed and returned.
  • The locator doesn’t track whether a service is currently being used.
  • Its main responsibility is finding or creating services, not reusing limited resources.

depending on its implementation. Its purpose is service discovery, not resource reuse.

 

Conclusion

The Pool Pattern is apowerful creational pattern that allows applications to reuse expensive objects instead of continuously creating and destroying them.

0 0 votes
Article Rating

What's your reaction?

Excited
0
Happy
0
Not Sure
0
Confused
0

You may also like

Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted