Avoiding conventions with lazy loading

To clarify, I mean something like:

class foon { private $barn = null; public function getBarn() { if (is_null($this->barn)) { $this->barn = getBarnImpl(); } return $this->barn; } } 

This is especially nice when you do not always need getBarn , and getBarn especially expensive (for example, it has a database call). Is there a way to avoid the conditional? It takes up a lot of space, looks ugly, and the disappearance of conditional states is always nice. Is there any other paradigm for handling this lazy load that I just don't see?

+7
source share
6 answers

Using the small php __call() method, we can easily write a decorator object that intercepts all method calls and caches the return values.

I once did something like this:

 class MethodReturnValueCache { protected $vals = array(); protected $obj; function __construct($obj) { $this->obj = $obj; } function __call($meth, $args) { if (!array_key_exists($meth, $this->vals)) { $this->vals[$meth] = call_user_func_array(array($this->obj, $meth), $args); } return $this->vals[$meth]; } } 

then

 $cachedFoon = new MethodReturnValueCache(new foon); $cachedFoon->getBarn(); 
+2
source

I thought about this from time to time, but of course I canโ€™t think about it. If you do not want to create one function to process this array using arrays and reflective properties.

+1
source

return ( $this->barn = $this->barn ? $this->barn : getBarn() );

or php 5.3 (?) one:

return ( $this->barn = $this->barn ?: getBarn() );

+1
source

You can do:

 return $this->barn != null ? $this->barn : ($this->barn = self::getBarnImpl()); 

But I do not understand how it is better.

+1
source

I donโ€™t think Iโ€™ve ever seen a method to completely eliminate this type of lazy initialization check, but it's interesting to think about. With a toy sample, there is no advantage, but in large objects you could reorganize the lazy initialization behavior either to the object to be initialized, or (more interestingly) to some general lazy initializer template (I present something approximately like a singlet) . In principle, if they did not decide to build it as a language construct (in this case it will still be present, only hidden), I think that you can best do the encapsulation of the code yourself.

 class LazyObject { ... public function __construct($type, $args) { $this->type = $type; ... } public getInstance() { if (empty($this->instance)) $this->instance = new $this->type($args); return $instance; } } class AggregateObject { private $foo; private $bar; public function __construct() { $this->foo = new LazyObject('Foo'); $this->bar = new LazyObject('Bar'); } public function getFoo() { return $this->foo->getInstance(); } ... } 
+1
source

Method1

I can think of a listener class.

 Constructor () { object = null listener = new Object() { // this is called once object = init() listener = new Object() { // next time do-nothing() // this is called } } Object get() { listener.invoke() return object 

This has no status checks, but it adds an extra field for each object, effectively duplicating memory consumption, while the stupid punishment of calling useless listener.invoke() code is preserved. I do not know how to remove it with all the polymorphism. Since the get() method is used by all instances of the class, it cannot be changed.

Method2

On-demand Java initialization using lazy class loading.

Bottom row

So, it seems that alternatives are worse than conditional, because modern processors optimize branch forecasts. Thus, the penalty check will be very tiny, I expect as soon as the code is initialized, and the branch always goes in one direction. A fake branch will only be accepted once during initialization, and it will also be short compared to your initialization time. Otherwise, you may not want to delay initialization.

+1
source

All Articles