Skip to content

Commit

Permalink
add lazy loading
Browse files Browse the repository at this point in the history
  • Loading branch information
Doug Nelson committed Jun 12, 2020
1 parent 9b60e63 commit 9d4e367
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 29 deletions.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"ext-json": "*",
"pimple/pimple": "~3.0",
"symfony/yaml": "^2.4|~3|~4",
"psr/simple-cache": "^1.0"
"psr/simple-cache": "^1.0",
"ocramius/proxy-manager": "^2.8"
},
"require-dev": {
"phpunit/phpunit": "~8",
Expand Down
74 changes: 48 additions & 26 deletions src/ContainerBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,51 +4,46 @@

use Pimple\Container;
use Silktide\Syringe\Exception\ReferenceException;
use ProxyManager\Factory\LazyLoadingValueHolderFactory;

class ContainerBuilder
{
/**
* Default class name for the container
*/
const DEFAULT_CONTAINER_CLASS = "Pimple\\Container";
const DEFAULT_CONTAINER_CLASS = Container::class;

private function getLazyLoadingValueHolderFactory() : LazyLoadingValueHolderFactory
{
static $factory;
if (!isset($factory)) {
$factory = new LazyLoadingValueHolderFactory();
}
return $factory;
}

public function populateContainer(Container $container, CompiledConfig $compiledConfig)
{
//
// Do the parameters!
//
foreach ($compiledConfig->getParameters() as $key => $value) {
$container[$key] = function () use ($value){
return $value;
};
}

foreach ($compiledConfig->getServices() as $key => $definition) {
$container[$key] = function () use ($container, $definition) {
$isFactoryCreated = isset($definition["factoryMethod"]);

$arguments = $this->resolveArray($container, $definition["arguments"] ?? []);

if ($isFactoryCreated) {
$service = call_user_func_array(
[
$definition["factoryClass"] ?? $container->offsetGet(mb_substr($definition["factoryService"], 1)),
$definition["factoryMethod"]
],
$arguments
$container[$key] = (function () use ($container, $definition) {
if ($definition["lazy"] ?? false) {
return $this->getLazyLoadingValueHolderFactory()->createProxy(
$definition["class"],
function (&$wrappedObject, $proxy, $method, $parameters, &$initializer) use ($container, $definition) {
$wrappedObject = $this->buildService($container, $definition);
$initializer = null; // turning off further lazy initialization
}
);
} else {
$service = (new \ReflectionClass($definition["class"]))->newInstanceArgs($arguments);
}

foreach ($definition["calls"] ?? [] as $call) {
call_user_func_array(
[$service, $call["method"]],
$this->resolveArray($container, $call["arguments"] ?? [])
);
}
return $service;
};
return $this->buildService($container, $definition);
});
}

foreach ($compiledConfig->getTags() as $tag => $services) {
Expand All @@ -66,6 +61,33 @@ public function populateContainer(Container $container, CompiledConfig $compiled
return $container;
}

private function buildService(Container $container, array $definition)
{
$isFactoryCreated = isset($definition["factoryMethod"]);

$arguments = $this->resolveArray($container, $definition["arguments"] ?? []);

if ($isFactoryCreated) {
$service = call_user_func_array(
[
$definition["factoryClass"] ?? $container->offsetGet(mb_substr($definition["factoryService"], 1)),
$definition["factoryMethod"]
],
$arguments
);
} else {
$service = (new \ReflectionClass($definition["class"]))->newInstanceArgs($arguments);
}

foreach ($definition["calls"] ?? [] as $call) {
call_user_func_array(
[$service, $call["method"]],
$this->resolveArray($container, $call["arguments"] ?? [])
);
}
return $service;
}

protected function resolveArray(Container $container, array $array)
{
$arguments = [];
Expand Down
5 changes: 3 additions & 2 deletions src/FileConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ class FileConfig
"abstract" => 1,
"calls" => 1,
"tags" => 1,
"override" => 1
"override" => 1,
"lazy" => 1
];

protected $filename;
Expand Down Expand Up @@ -151,7 +152,7 @@ public function validate()
{
foreach ($this->keys as $key) {
if (!isset(self::ACCEPTABLE_KEYS[$key])) {
throw new ConfigException($key." is not a valid services key");
throw new ConfigException($key." is not a valid config key");
}
}

Expand Down
18 changes: 18 additions & 0 deletions tests/integration/Lazy/LazyClass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace Silktide\Syringe\IntegrationTests\Lazy;

class LazyClass
{
public static $loaded = false;

public function __construct()
{
self::$loaded = true;
}

public function getTrue() : bool
{
return true;
}
}
29 changes: 29 additions & 0 deletions tests/integration/Lazy/LazyTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php


namespace Silktide\Syringe\IntegrationTests\Lazy;


use PHPUnit\Framework\TestCase;
use Silktide\Syringe\IntegrationTests\Examples\ExampleClass;
use Silktide\Syringe\Syringe;

class LazyTest extends TestCase
{
public function testLazyLoading()
{
$container = Syringe::build([
"paths" => [__DIR__],
"files" => ["file1.yml"]
]);

/**
* @var LazyClass $myService
*/
$myService = $container["my_service"];
$this->assertInstanceOf(LazyClass::class, $myService);
$this->assertFalse(LazyClass::$loaded);
$myService->getTrue();
$this->assertTrue(LazyClass::$loaded);
}
}
4 changes: 4 additions & 0 deletions tests/integration/Lazy/file1.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
services:
my_service:
class: Silktide\Syringe\IntegrationTests\Lazy\LazyClass
lazy: true

0 comments on commit 9d4e367

Please sign in to comment.