Introducing the Lazy Loading Pattern

Welcome to the third part of a five-part series on lazy and eager loading in PHP 5. In this part of the series, you’ll learn about the lazy design pattern, and how to use it effectively in your applications.

Very often, the terms “lazy” and “eager” are used in daily talking to define or qualify the way that certain people are, or simply to judge their behaviors and reactions in response to a number of situations that occur in life. The truth is that we, as individuals, are an interesting mixture of these two characteristics.

Also, it’s true that human beings try to translate these concepts to other areas, such as software programming. If you’ve ever developed web-based or desktop applications using your favorite compiled or interpreted language, then it’s possible that you’ve already coded “factory” methods to create one or multiple objects, or even defined a few “Observer” and “Dispatcher” modules as well.

Definitively, many design patterns like the ones mentioned above respond to simple translations of human behaviors within the terrain of software development, and certainly “lazy” and “eager” aren’t the exception. In general, when an application uses lazy loading, it means that it delays or defers the loading of a specific resource until it’s really required at runtime. On the other hand, if the same application (or a part of it) relies on eager loading, then it implies that the resource will be loaded as soon as possible, regardless of whether or not it has been requested.

Of course, it’s possible to extend the concepts of “lazy” and “eager” when working with classes, which leads to using approaches commonly known as lazy and eager instantiations respectively. In the case of PHP 5, implementing lazy and eager loading is truly a no-brainer process, and the result of this implementation can be either successful or amazingly poor, depending on the context in which these patterns are applied.

Precisely, in the previous chapter of this series I developed an example that showed that there are times when including eagerly a class within a script can be pretty inefficient, especially if an instance of the class is created by the script in question right before it finishes its execution.

Nonetheless, it’s possible to use the benefits of lazy loading to address an issue like this very easily, and that’s exactly what I’m going to show you in the lines to come. So, if the topic interests you, start reading to find out more on it!

{mospagebreak title=Review: object-oriented lazy loading}

Before I begin demonstrating how to improve the efficiency of the sample script developed in the previous installment of the series by applying the concept of lazy loading, it would be helpful to reintroduce the full source code of that particular example as a review. 

Below you’ll find the definition of the class that is eagerly loaded by the aforementioned script, which actually does nothing except store data about some hypothetical users. Here it is:

class User {

 

private $fname = ‘Alejandro’;

private $lname = ‘Gervasio’;

private $email = ‘alejandro@mydomain.com’;

 

public function __construct($fname = ”, $lname = ”, $email = ”)

{

if (is_string($fname) and !empty($fname))

{

$this->fname = $fname;

}

if (is_string($lname) and !empty($lname))

{

$this->lname = $lname;

}

if (is_string($email) and !empty($email))

{

$this->email = $email;

}

}

 

// get user’s first name

public function getFirstName()

{

return $this->fname;

}

 

// get user’s last name

public function getLastName()

{

return $this->lname;

}

 

// get user’s email

public function getEmail()

{

return $this->email;

}

 

// display user data

public function __toString()

{

return ‘First Name: ‘ . $this->fname . ‘<br />Last Name: ‘ . $this->lname . ‘<br />Email: ‘ . $this->email;

}

}

As I mentioned before, the functionality of the above “User” class is limited to storing information about a particular user via its “fname,” “lname” and “email” properties, which also can be retrieved thanks to the implementation of the corresponding getter methods.

However, since the logic of this class is very easy to follow, I’m not going to waste more time explaining how it functions. Instead, it’s time to go one step further and show the source code of a loader module that will be used at a later time for including the “User” class. Here’s the definition of this simple module:

// create custom FileNotFoundException exception class

class FileNotFoundException extends Exception {}

 

// create custom ClassNotFoundException exception class

class ClassNotFoundException extends Exception {}

 

// define ‘Loader’ class

class Loader {

 

public static function load($class)

{

if (class_exists($class, FALSE))

{

return;

}

$file = $class . ‘.php’;

if(!file_exists($file))

{

throw new FileNotFoundException(‘File ‘ . $file . ‘ not found.’);

}

require $file;

unset($file);

if (!class_exists($class, FALSE))

{

eval(‘class ‘ . $class . ‘{}’);

throw new ClassNotFoundException(‘Class ‘ . $class . ‘ not found.’);

}

}

}

Basically, all that this module does is include on demand a specified class via a PHP require. In addition, it defines a couple of exception subclasses to throw custom exceptions when attempting to load a certain class. You should have no trouble understanding this process. 

Finally, here’s the script that uses the functionality of the previous loader module to eagerly include the “User” class shown previously. Look at it, please:

try {

// load eagerly ‘User’ class

Loader::load(‘user’);

/*

rest of logic goes here

*/

// create instance of ‘User’ class

$user = new User(‘Mary’, ‘Smith’, ‘mary@domain.com’);

echo $user;

}

catch (FileNotFoundException $e){

echo $e->getMessage();

exit();

}

 

catch (ClassNotFoundException $e){

echo $e->getMessage();

exit();

}

If you ask yourself what’s the big deal with this script, my answer would be simply …nothing. However, the script actually does do something that deserves a closer look. As you can see, at the very beginning it calls the static “load()” method that belongs to “Loader” to include the “User” class, even though an instance of it is only created when the script finishes its execution.

This shows in a nutshell the logic that stands behind using the eager loading pattern, which in this particular example is applied to include a basic class. Though, as I said in the introduction, eager loading can be utilized in many different cases, such as instantiating classes, prefetching database rows, and so forth.

In the previous example, eager loading causes a detriment to the performance of the sample script, since the class is loaded first, without taking into account whether or not an instance of it will be required. The question that brings up here is, can this issue be fixed with only minor hassles?

Fortunately, the answer is yes! By applying the opposite pattern, that is lazy loading, it’s possible to rewrite the previous script so it can load the “User” class if and only if it’s requested at runtime.

Want to learn how this can be accomplished in a few steps? Then click on the link that appears below and read the section to come.

{mospagebreak title=Introducing the lazy loading pattern}

To apply the lazy loading pattern within the script that you learned before, it’s necessary to introduce a subtle change into the corresponding loader module. Basically, this modification will consist of registering the “load()” method of the “Loader” class with the “spl_autoload_register()” PHP function, so the method in question can be called automatically when a script attempts to include a class on demand.

Having explained that, here’s the enhanced definition of the loader module:

// create custom FileNotFoundException exception class

class FileNotFoundException extends Exception {}

 

// create custom ClassNotFoundException exception class

class ClassNotFoundException extends Exception {}

 

spl_autoload_register(array(‘Loader’,'load’));

 

// define ‘Loader’ class

class Loader {

 

public static function load($class)

{

if (class_exists($class, FALSE))

{

return;

}

$file = $class . ‘.php’;

if(!file_exists($file))

{

throw new FileNotFoundException(‘File ‘ . $file . ‘ not found.’);

}

require $file;

unset($file);

if (!class_exists($class, FALSE))

{

eval(‘class ‘ . $class . ‘{}’);

throw new ClassNotFoundException(‘Class ‘ . $class . ‘ not found.’);

}

}

}

That was really simple to code and read, wasn’t it? At this point, the loader module has suddenly turned into a true autoloader mechanism that will include a specified class on request, thanks to the use of the aforementioned “spl_autoload_register()” PHP function.

Believe it or not, this small modification into the source code of the module permits to easily build scripts, or even entire applications, that include classes only when they are really required — or in other words, that implement the lazy loading pattern.

But if you’re like me, you now want to see how the revamped version of the previous loader module can be put to work with the “User” class. Am I right? Great! In the last section of this article I’m going to create a basic script that will load that class in a lazy manner.

To see how this script will be developed, go ahead and read the next section.

{mospagebreak title=Lazy loading in action}

In reality, building a script that lazy-loads the previous “User” class is a straightforward process that can be accomplished in a few simple steps, thanks to the brand new functionality that I gave the pertinent loader module.

To demonstrate the veracity of my claim, below I coded that script for you, so you can quickly grasp how it works. Here it is:

// create instance of ‘User’ class only when the script requires it

try {

// create instance of ‘User’ class

$user = new User();

echo $user;

}

catch (FileNotFoundException $e){

echo $e->getMessage();

exit();

}

 

catch (ClassNotFoundException $e){

echo $e->getMessage();

exit();

}

Do you realize how simple it is to switch from a script that eagerly loads a sample class to another one that lazy-loads it? And the best part is that this change was accomplished by means of a small modification introduced in the loader module. What else can one ask for?

Feel free to tweak all of the code samples that you saw in this tutorial. Doing so will give you a better understanding of how to apply the lazy loading pattern in PHP 5. The experience will be pretty educational, believe me.

Final thoughts

In this third episode of the series, I explained how to improve the performance of a script in PHP 5 by using the lazy loader pattern. As you saw for yourself, the proper usage of the pattern allowed us to include a class only when it was requested, thus avoiding unnecessary overheads during the script’s execution.

Logically, it’s possible to utilize the pattern when instantiating classes, a procedure not surprisingly known as lazy instantiation. Nonetheless, this topic is outside of the scope of this series of articles, so it’s time to focus on the concepts that will be deployed in the upcoming part.

In that tutorial, I’m going to discuss how to use eager loading when working with the properties of a class. So, here’s my little piece of advice: don’t miss the next article!

Google+ Comments

Google+ Comments