Skip to content

Commit

Permalink
Introduce "global resolved classes" concept
Browse files Browse the repository at this point in the history
  • Loading branch information
Chemaclass committed Jul 17, 2021
1 parent 3b5bbf1 commit 318ae13
Show file tree
Hide file tree
Showing 7 changed files with 203 additions and 6 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@
/.idea/
/.vscode/
/vendor/
/data/
/.phpbench/
.phpunit.*
.php_cs.cache
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,6 @@
"phpstan": "./vendor/bin/phpstan analyze -c phpstan.neon src",
"csfix": "./vendor/bin/php-cs-fixer fix --allow-risky=yes",
"csrun": "./vendor/bin/php-cs-fixer fix --allow-risky=yes --dry-run",
"benchmark": "./vendor/bin/phpbench run tests/Benchmark"
"phpbench": "vendor/bin/phpbench run --report=aggregate --ansi"
}
}
22 changes: 20 additions & 2 deletions phpbench.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
{
"runner.bootstrap": "vendor/autoload.php"
}
"runner.bootstrap": "vendor/autoload.php",
"runner.path": "tests/Benchmark/",
"runner.retry_threshold": 5,
"runner.iterations": 3,
"runner.revs": 10,
"runner.time_unit": "time",
"runner.assert": [
"mode(variant.time.avg) <= mode(baseline.time.avg) +/- 15%"
],
"report.generators": {
"all": {
"generator": "composite",
"reports": [
"env",
"default",
"aggregate"
]
}
}
}
26 changes: 25 additions & 1 deletion src/Framework/ClassResolver/AbstractClassResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,16 @@ abstract class AbstractClassResolver
protected static array $cachedInstances = [];
protected static ?ClassNameFinderInterface $classNameFinder = null;

/** @var array<string,object> */
private static array $globalResolvedClasses = [];

abstract public function resolve(object $callerClass): ?object;

public static function addGlobal(string $key, object $resolvedClass): void
{
self::$globalResolvedClasses[$key] = $resolvedClass;
}

/**
* @return null|mixed
*/
Expand All @@ -29,7 +37,7 @@ public function doResolve(object $callerClass)
$resolvedClassName = $this->findClassName($classInfo);

if (null === $resolvedClassName) {
return null;
return $this->resolveGlobal($cacheKey);
}

self::$cachedInstances[$cacheKey] = $this->createInstance($resolvedClassName);
Expand All @@ -39,6 +47,22 @@ public function doResolve(object $callerClass)

abstract protected function getResolvableType(): string;

/**
* @return null|mixed
*/
private function resolveGlobal(string $cacheKey)
{
$resolvedClass = self::$globalResolvedClasses[$cacheKey] ?? null;

if (null === $resolvedClass) {
return null;
}

self::$cachedInstances[$cacheKey] = $resolvedClass;

return self::$cachedInstances[$cacheKey];
}

private function getCacheKey(ClassInfo $classInfo): string
{
return $classInfo->getCacheKey($this->getResolvableType());
Expand Down
20 changes: 18 additions & 2 deletions src/Framework/ClassResolver/ClassInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

namespace Gacela\Framework\ClassResolver;

use function array_slice;
use function count;
use function get_class;

final class ClassInfo
{
private ?string $cacheKey = null;
Expand All @@ -13,16 +17,28 @@ final class ClassInfo
public function __construct(object $callerObject)
{
$callerClass = get_class($callerObject);

/** @var string[] $callerClassParts */
$callerClassParts = explode('\\', ltrim($callerClass, '\\'));
if (count($callerClassParts) <= 1) {
$callerClassParts = [
'module-name@anonymous',
'class-name@anonymous',
];
}

$this->callerNamespace = implode('\\', array_slice($callerClassParts, 0, count($callerClassParts) - 1));
$this->callerModuleName = $callerClassParts[count($callerClassParts) - 2];
$this->callerModuleName = $callerClassParts[count($callerClassParts) - 2] ?? '';
}

public function getCacheKey(string $resolvableType): string
{
if (!$this->cacheKey) {
$this->cacheKey = $this->getFullNamespace() . $this->getModule() . $resolvableType;
$this->cacheKey = sprintf(
'\\%s\\%s',
$this->getFullNamespace(),
$resolvableType
);
}

return $this->cacheKey;
Expand Down
69 changes: 69 additions & 0 deletions tests/Benchmark/Framework/ClassResolver/AbstractFacadeBench.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

declare(strict_types=1);

namespace GacelaTest\Benchmark\Framework\ClassResolver;

use Gacela\Framework\AbstractConfig;
use Gacela\Framework\AbstractFacade;
use Gacela\Framework\AbstractFactory;
use Gacela\Framework\ClassResolver\AbstractClassResolver;

/**
* @BeforeMethods("setUp")
* @Revs(100)
* @Iterations(5)
*/
final class AbstractFacadeBench
{
private AbstractFacade $facade;

public function setUp(): void
{
AbstractClassResolver::addGlobal(
'\module-name@anonymous\Config',
new class() extends AbstractConfig {
public function getValues(): array
{
return ['1', 2, '3'];
}
}
);

AbstractClassResolver::addGlobal(
'\module-name@anonymous\Factory',
new class() extends AbstractFactory {
public function createDomainClass(): object
{
return new class($this->getConfig()) {
private AbstractConfig $config;

public function __construct(AbstractConfig $config)
{
$this->config = $config;
}

public function getConfigValues(): array
{
return $this->config->getValues();
}
};
}
}
);

$this->facade = new class() extends AbstractFacade {
public function getSomething(): array
{
return $this->getFactory()
->createDomainClass()
->getConfigValues();
}
};
}

public function bench_class_resolving(): void
{
$this->facade->getSomething();
}
}
68 changes: 68 additions & 0 deletions tests/Integration/Framework/GlobalServices/GlobalServicesTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

declare(strict_types=1);

namespace GacelaTest\Integration\Framework\GlobalServices;

use Gacela\Framework\AbstractConfig;
use Gacela\Framework\AbstractFacade;
use Gacela\Framework\AbstractFactory;
use Gacela\Framework\ClassResolver\AbstractClassResolver;
use PHPUnit\Framework\TestCase;

final class GlobalServicesTest extends TestCase
{
private AbstractFacade $facade;

public function setUp(): void
{
AbstractClassResolver::addGlobal(
'\module-name@anonymous\Config',
new class() extends AbstractConfig {
public function getValues(): array
{
return ['1', 2, [3]];
}
}
);

AbstractClassResolver::addGlobal(
'\module-name@anonymous\Factory',
new class() extends AbstractFactory {
public function createDomainClass(): object
{
return new class($this->getConfig()) {
private AbstractConfig $config;

public function __construct(AbstractConfig $config)
{
$this->config = $config;
}

public function getConfigValues(): array
{
return $this->config->getValues();
}
};
}
}
);

$this->facade = new class() extends AbstractFacade {
public function getSomething(): array
{
return $this->getFactory()
->createDomainClass()
->getConfigValues();
}
};
}

public function test_factory(): void
{
self::assertSame(
['1', 2, [3]],
$this->facade->getSomething()
);
}
}

0 comments on commit 318ae13

Please sign in to comment.