Object pool design pattern in PHP, Learn design patterns

This article with guide you through the object pool design pattern PHP, with theory explanation, and the practical example as well.

Object Pool design pattern in PHP

Object pool design pattern is a concept which essentially proposes the reuse of existing objects, instead of creating lots of new ones. It belongs to the category of creational design patterns. Within this pattern category we have:

This pattern is used in situations where the creation of an object is considered as an “expensive operation”, i.e. initialization of objects takes lots of time.

Meaning, we can use pool design pattern when:

  • The cost of initialization of an object is high
  • We are expecting a high number of instances (lots of objects)
  • The number of objects that we use in time is low (limited)

The idea behind pool design pattern is simple:

  • We create a pool that has a limited number of reusable objects.
  • The client asks for a reusable object from a pool.

Sign up for my newsletter because you want to get some quality content served right into your mailbox. Give it a try, it is a great way to improve your development and business skills. Just like a warm cup of tea in the evening, it will do good for you. Even better, you will get the latest news, updates, and promotions. No tea included. 🙂

Note: Your information is protected and I never spam, ever. You can view my privacy policy here.

Object Pool Design Pattern PHP Example

Firstly, we want to create Employee class.

Each employee will have id, personnelNumber, firstname and lastname.

Furthermore, each employee will have getters for parameters and getInfo() function which gives information about employee.

Finally, constructor of employee will have sleep(10) causing each object creation to take 10 seconds. This simulates expensive action, meaning we have to wait for some time before object is created.

This way, when we execute the example, we will clearly see which objects were already created in pool (we didn’t have to wait) and when there were no objects in pool (we had to wait 10 seconds to create a new object).

<?php

/**
 * Class Employee represents an entity class for a single employee.
 * This class will create objects that we can later use (either directly or in a pool).
 */
class Employee
{
    private $id;
    private $personnelNumber;
    private $firstname;
    private $lastname;

    /**
     * Employee constructor.
     *
     * @param $id
     * @param $personnelNumber
     * @param $firstname
     * @param $lastname
     */
    public function __construct($id, $personnelNumber, $firstname, $lastname)
    {
        $this->id = $id;
        $this->personnelNumber = $personnelNumber;
        $this->firstname = $firstname;
        $this->lastname = $lastname;

        echo "New employee '$this->firstname $this->lastname' is being created, we need to wait 10 seconds. \n";
        sleep(10);
    }

    public function getId()
    {
        return $this->id;
    }

    public function getFirstname()
    {
        return $this->firstname;
    }

    public function getLastname()
    {
        return $this->lastname;
    }

    public function getPersonnelNumber()
    {
        return $this->personnelNumber;
    }

    public function getInfo()
    {
        echo "$this->id : Employee $this->firstname $this->lastname has personnel number $this->personnelNumber \n";
    }
}

Then, we will implement EmployeePool class.

This class has array of $availableEmployees and array of $busyEmployees.

Furthermore, this class has getEmployee() function and release(Employee $employee) function.

First function provides employee, either by creating a new object, or providing an existing object, if there is one available. This function represents the core implementation of object pool pattern.

Release function simply releases object, making it available for future use.

<?php

/**
 * Class EmployeePool
 */
class EmployeePool
{
    private $busyEmployees;
    private $availableEmployees;

    private $personnelNumbers = [ 'A101', 'A102', 'A103', 'A104', ];
    private $firstnames = [ 'John', 'Johana', 'Milan', 'Milana', ];
    private $lastnames = [ 'Doe', 'Latinovic', 'Nickelson', ];

    /**
     * EmployeePool constructor.
     */
    public function __construct()
    {
        $this->busyEmployees = [];
        $this->availableEmployees = [];
    }

    /**
     * @return Employee|mixed
     */
    public function getEmployee()
    {
        if (0 === count($this->availableEmployees)) {
            echo "There are no available employees in pool, we need to create/hire one. \n";
            $id = count($this->availableEmployees) + count($this->busyEmployees) + 1;
            $personnelNumber = $this->personnelNumbers[array_rand($this->personnelNumbers, 1)];
            $firstname = $this->firstnames[array_rand($this->firstnames, 1)];
            $lastname = $this->lastnames[array_rand($this->lastnames, 1)];
            $employee = new Employee($id, $personnelNumber, $firstname, $lastname);
        }
        else {
            echo "There are available employees in pool, we will pick one of them. \n";
            $employee = array_pop($this->availableEmployees);
        }
        $this->busyEmployees[$employee->getId()] = $employee;

        return $employee;
    }

    /**
     * @param $employee
     */
    public function release($employee)
    {
        $id = $employee->getId();
        $firstname = $employee->getFirstname();
        $lastname = $employee->getLastname();

        if (isset($this->busyEmployees[$id])) {
            unset($this->busyEmployees[$id]);
            $this->availableEmployees[$id] = $employee;
        }

        echo "Employee $firstname $lastname has been released, meaning he is again available. \n";
    }

    /**
     *
     */
    public function getPoolStatus()
    {
        $numberOfAvailableEmployees = count($this->availableEmployees);
        $numberOfBusyEmployees = count($this->busyEmployees);

        echo "Pool has $numberOfAvailableEmployees available employees and $numberOfBusyEmployees busy employees. \n";
    }
}

Finally, we want to create Main.php class which represents a simple example where we want to use EmployeePool.

Concept is simple, we have job that needs to be done.

For that, we will hire several employees by asking EmployeePool to provide us with them. Then, when some of them are finished with work, we will release them.

However, we will have some more additional tasks to do, so we will ask EmployeePool for new employees again. But this time, EmployeePool will already have some employees (created objects but currently not in use) and we will get these objects.

<?php

require_once("Employee.php");
require_once("EmployeePool.php");

$pool = new EmployeePool();

$employee1 = $pool->getEmployee();
$pool->getPoolStatus();

$employee2 = $pool->getEmployee();
$pool->getPoolStatus();

$employee3 = $pool->getEmployee();
$pool->getPoolStatus();

$employee4 = $pool->getEmployee();
$pool->getPoolStatus();

$pool->release($employee2);
$pool->release($employee3);

$employee5 = $pool->getEmployee();
$pool->getPoolStatus();

$employee6 = $pool->getEmployee();
$pool->getPoolStatus();

$employee7 = $pool->getEmployee();
$pool->getPoolStatus();

//echo "Employee 1: " . $employee1->getInfo() . "\n";
//echo "Employee 2: " . $employee2->getInfo() . "\n";
//echo "List of occupied employees: " . $pool->getBusyEmployees() . "\n";
//echo "List of free employees: " . $pool->getAvailableEmployees() . "\n";

Finally, we will get this result in console.

There are no available employees in pool, we need to create/hire one.
New employee 'Milana Latinovic' is being created, we need to wait 10 seconds.
Pool has 0 available employees and 1 busy employees.

There are no available employees in pool, we need to create/hire one.
New employee 'Milana Nickelson' is being created, we need to wait 10 seconds.
Pool has 0 available employees and 2 busy employees.

There are no available employees in pool, we need to create/hire one.
New employee 'Johana Nickelson' is being created, we need to wait 10 seconds.
Pool has 0 available employees and 3 busy employees.

There are no available employees in pool, we need to create/hire one.
New employee 'Milana Nickelson' is being created, we need to wait 10 seconds.
Pool has 0 available employees and 4 busy employees.

Employee Milana Nickelson has been released, meaning he is again available.

Employee Johana Nickelson has been released, meaning he is again available.

There are available employees in pool, we will pick one of them.
Pool has 1 available employees and 3 busy employees.

There are available employees in pool, we will pick one of them.
Pool has 0 available employees and 4 busy employees.

There are no available employees in pool, we need to create/hire one.
New employee 'John Doe' is being created, we need to wait 10 seconds.
Pool has 0 available employees and 5 busy employees.

References

There is an interesting read about the object pool design pattern at source making. Also, there is a blog post on achieving better performance with an object pool design pattern.

Finally, you can find the latest version of this code in the design patterns code repository.