Ocramius ProxyManager or the great library that does the heavy lazy loading lifting for you
Within the next few lines, I will show you how you can use the proxy manager and how low the setup fee is compared to self written code.
The setup fee
Give is, that you have installed the ProxyManager with Composer. Than, create a script like the following (I will name it foo.php because I like it ;-)).
<?php
/**
* @author stev leibelt <artodeto@bazzline.net>
* @since 2017-12-12
*/
require_once __DIR__ . '/vendor/autoload.php';
use ProxyManager\Factory\LazyLoadingValueHolderFactory;
use ProxyManager\Configuration;
$configuration = new Configuration();
$configuration->setProxiesTargetDir(
__DIR__ . '/../cache'
);
spl_autoload_register(
$configuration->getProxyAutoloader()
);
class A
{
/** @var mixed */
private $foo;
public function __construct(
$foo
) {
echo __METHOD__ . PHP_EOL;
echo 'Something will take very long.' . PHP_EOL;
sleep(5);
$this->foo = $foo;
echo 'Done.' . PHP_EOL;
}
public function __call($name, $arguments)
{
echo __METHOD__ . sprintf(
'name: >>%s<<, list of arguments: >>%s<<.',
$name,
implode(
',',
$arguments
)
) . PHP_EOL;
}
public function foo()
{
echo $this->foo . PHP_EOL;
}
}
class B extends A
{
/** @var mixed */
private $constructorFoo;
/** @var bool */
private $isNotInstantiated;
public function __construct(
$foo
) {
echo __METHOD__ . PHP_EOL;
echo 'Superfast.' . PHP_EOL;
$this->constructorFoo = $foo;
$this->isNotInstantiated = true;
echo 'Done.' . PHP_EOL;
}
public function __call($name, $arguments)
{
$this->instantiateIfNeeded();
parent::__call($name, $arguments); // TODO: Change the autogenerated stub
}
public function foo()
{
$this->instantiateIfNeeded();
parent::foo(); // TODO: Change the autogenerated stub
}
private function instantiateIfNeeded()
{
if ($this->isNotInstantiated) {
parent::__construct(
$this->constructorFoo
);
$this->isNotInstantiated = false;
}
}
}
echo ':: Construct A' . PHP_EOL;
$a = new A('a');
echo ':: Construct B' . PHP_EOL;
$b = new B('b');
echo ':: Construct C' . PHP_EOL;
$factory = new LazyLoadingValueHolderFactory(
$configuration
);
$c = $factory->createProxy(
A::class,
function (& $wrappedObject, $proxy, $method, $parameters, & $initializer) {
$wrappedObject = new A('c'); // instantiation logic here
$initializer = null; // turning off further lazy initialization
}
);
echo ':: Begin A' . PHP_EOL;
$a->foo();
$a->bar('foo', 'bar', 'baz');
echo ':: End A' . PHP_EOL;
echo ':: Begin B' . PHP_EOL;
$b->foo();
$b->bar('foo', 'bar', 'baz');
echo ':: End B' . PHP_EOL;
echo ':: Begin C' . PHP_EOL;
$c->foo();
$c->bar('foo', 'bar', 'baz');
echo ':: End C' . PHP_EOL;
And finally, execute it (clear && php foo.php).
What have we done - the explanation of the script
First, we are creating a class "A" that does some complicated stuff. Than, we are trying to implement our own lazy loading logic by creating a class "B". Afterwards we are instantiating A, B and A with the proxy manager. Finally, we are calling two methods for each instantiation.
When you execute the script, you quickly will figure out that the instantiation of $a is taking as long as expected while $b and $c are almost instantly there. At the end $b and $c will react the same.
Why should you use the proxy manager if you can archive the same stuff with "just some lines of code"? Because the proxy manager reduced your maintenance coast. If "A" would change, you would have need to extend or change "B" as well (e.g. A gets another method) while you don't have to touch any piece of code when using the proxy manager. Secondly, proxy manager is well tested and used. If you find an issue, you can fix it since the code is open source and do something good for the world - because sharing is caring.