Was doing a(nother) shopping application lately. In the application each Product (a class) can have many images, but they’re not displayed in the search results page or the basket page, so it seemed a bit daft to be reading the database and loading them into memory in the constructor.
What I did instead was to use the magic method __get() to load the images into the object when they were needed. __get() is called whenever something tries to access a variable that is not set or publically accessible, so basically I used that to load the images whenever some other piece of code tried to access Product::images.
Here’s the actual code:
public function __get($var)
{
eval("$this->_load".$var."();");
$this->{"_load".$var}();
return $this->$var;
}
So if some other piece of code made a Product object called $product and then tried to access $product->images and the images haven’t already been loaded, a (private) function called $product->_loadimages() is called. If the images HAVE already been loaded then __get() is not called.
Very handy.
One other thing I had to so was to unset() Product::images in the constructor, so that __get() would be called when something tried to access it. I could have avoided this by making $images private, but it behaves as a public property so I didn’t want to.
August 8, 2008 at 9:24 pm
[…] Cormac posted this look at a method for lazy loading on variables in an object with the magic __get method. I used the magic […]
August 9, 2008 at 8:14 am
[…] In response to Lazy loading of object variables in php using __get() […]
August 9, 2008 at 4:29 pm
eval() is evil. This is a better way:
$this->{‘_load’ . $var}();
return $this->$var;
August 9, 2008 at 7:04 pm
Why don’ you just use
public function __get($var)
{
$loader = ‘_load’.$var;
$this->$loader();
return $this->$var;
}
it should be much faster than using eval and much portable without the placeholders {}
August 10, 2008 at 5:40 pm
You know you can remove the eval() call and replace it with:
$method();
?>
August 10, 2008 at 5:41 pm
Yeah your blog killed my opening ?php,
$method = ‘_load’ . $var;
$this->$method();
August 11, 2008 at 12:28 pm
Don’t use eval. You are just asking for trouble. Instead you should first check that the method exists and then call it using call_user_func().
if (is_callable(array($this, ‘_load’ . $var)))
{
call_user_func(array($this, ‘_load’ . $var));
}
return $this->$var;
August 11, 2008 at 1:03 pm
Whoa! I didn’t realise anyone read this blog
Anyway, ok, I shouldn’t have used eval(). My bad.
December 25, 2008 at 8:29 pm
“Whoa! I didn’t realise anyone read this blog”
You’re 10th hit on google for “php lazy load”
August 6, 2009 at 8:47 am
Great article, and informative comments to go with it.
August 16, 2010 at 1:34 pm
Now the 3rd for ‘PHP lazy loading’ on Google.com
September 13, 2010 at 9:34 am
First hit for ‘lazy loading php’ @ Google.
October 7, 2010 at 3:45 pm
This worked like a champ! Thank you!