PHP Closure and Lazy Loading

What is the Closures?

Let’s define firstly what is the anonymous function? If you are a front-end developer and have worked with JavaScript, you should be already familiar with anonymous functions. These pretty useful to write short inline functions, define callback etc.

An anonymous function is a function that was declared without any named identifier to refer to it. Here is the PHP implementation of anonymous function:

<?php
$anonymousfunctionReference = function(){
    echo "Anonymous function called"
};

echo $anonymousfunctionReference();

This should print “Anonymous function called”. In above example, the anonymous function actually returns a reference of Closure object, not only a function reference. Thus, the PHP closure method ‘bindTo‘ can be applied on this reference. The other ‘bind‘ method is static and alternate way to get the same behavior. So closure is nothing but an object representation of anonymous function. It is the object-oriented way to use anonymous function. Here is the example:

<?php
$func = function(){
    return ++($this->count);
};

class Test{
    private $count = 1;
}

$test = new Test();

$func1 = $func->bindTo($test, 'Test'); // specify class name
$func2 = $func->bindTo($test,  $test); // or object

echo $func1(); // This should print 2
echo $func2(); // This should print 3

What We Can Do With Closure?

  • Accessing private data of an object instance (Shown above as the second example using the bindTo function)
  • Lazy loading

Another simple example below will show you one of the super power of closure, accessing private variable of an object:

<?php
$func = function(){
    return $this->count;
};

class Test{
    private $count = 1;
}

$func1 = Closure::bind($func, new Test(), 'Test');  // specify class name
$func2 = Closure::bind($func, new Test(), $test); // or object

echo $func1(); // This should print 1
echo $func2(); // This should print 1

If we just know the variable name, we are able to use private data without modifying existing class. Same way we can add/inject new behavior to a php class without modifying it as well.

Lazy Loading in PHP with Closures

Let’s say we want to retrieve all addresses belongs to a customer.

<?php
// Client side code
$customer = $addressRepository->find($customerId); // Find the customer
$addresses = $customer->getAddresses(); // get the all address
// Server side code
<?php
class Customer
{
    // Assume that needed constructor is there and available

    public function getAddresses()
    {
        return $this->addresses;
    }

    public function setAddresses($addresses)
    {
        $this->addresses = $addresses
    }
}

class AddressRepository
{
    public function find($customerId)
    {
        $customerdata = $this->db->query('select * from Customer where customer_id = $customerId;');
        $customer = new Customer($customerdata);
        $addressesData = $this->db->query('select * from Address;');
        $addresses = array();

        foreach($addressesData as $address) {
            $addresses[] = new Address($address);
        }

        $customer->setAddress($addresses);
        return $customer;
    }
}

In the above code, Customer object holds an instance of the database adapter, and queries it for related Orders per ActiveRecord pattern. The downside of ActiveRecord, the tight coupling between Customer and the database makes it less portable, and hard to test. We always query the database for the Orders, even when we don’t need them.

In order to resolve above issue, we should move the logic for finding address into a Closure, push it into the Customer instance, and execute only when we actually need the addresses using Lazy Loading pattern with Closure. As we do this we keep our client code intact.

// Server side code
<?php
class Customer
{
    // Assume that needed constructor is there and available

    public function setAddressReference(Closure $addressesReference)
    {
        $this->addressesReference = $addressesReference;
    }

    public function getAddresses()
    {
        if(!isset($this->addresses))
        {
             $reference = $this->addressesReference;
             $this->addresses = $reference();
        }

        return $this->addresses;
    }

    public function setAddresses($addresses)
    {
        $this->addresses = $addresses
    }
}

class AddressRepository
{
    public function find($customerId)
    {
        $customerdata = $this->db->query('select * from Customer where customer_id = $customerId;');
        $customer = new Customer($customerdata);

        $addressesReference = function($customer) use($id, $db) {
            $addressesData = $this->db->query('select * from Address;');
            $addresses = array();

            foreach($addressesData as $address) {
                 $addresses[] = new Address($address);
            }

            return $addresses;
        };

        $customer->setAddressReference($addressesReference);
        return $customer;
    }
}

So, as you can see here, we can write all definitions, without actual initialization happen using the closure. Later when needed, use it with simple assignment as “$reference = $this->addressesReference; $this->addresses = $reference();”.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s