Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 54 additions & 11 deletions packages/container/src/GenericContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ final class GenericContainer implements Container
{
use HasInstance;

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

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

/** @var array<string, Initializer|DynamicInitializer|null> */
private array $initializerCache = [];

public function __construct(
/** @var ArrayIterator<array-key, mixed> $definitions */
private(set) ArrayIterator $definitions = new ArrayIterator(),
Expand Down Expand Up @@ -124,7 +133,7 @@ public function register(string $className, callable $definition): self

public function unregister(string $className, bool $tagged = false): self
{
unset($this->definitions[$className], $this->singletons[$className]);
unset($this->definitions[$className], $this->singletons[$className], $this->resolved[$className]);

if ($tagged) {
$singletons = array_filter(
Expand All @@ -134,6 +143,12 @@ public function unregister(string $className, bool $tagged = false): self
);

$this->setSingletons($singletons);

foreach (array_keys($this->resolved) as $key) {
if (str_starts_with($key, "{$className}#")) {
unset($this->resolved[$key]);
}
}
}

return $this;
Expand Down Expand Up @@ -262,7 +277,10 @@ private function invokeFunction(FunctionReflector|Closure $callback, mixed ...$p
public function addInitializer(ClassReflector|string $initializerClass): Container
{
if (! $initializerClass instanceof ClassReflector) {
$initializerClass = new ClassReflector($initializerClass);
if (! isset(self::$classReflectors[$initializerClass])) {
self::$classReflectors[$initializerClass] = new ClassReflector($initializerClass);
}
$initializerClass = self::$classReflectors[$initializerClass];
}

// First, we check whether this is a DynamicInitializer,
Expand Down Expand Up @@ -292,7 +310,10 @@ public function addInitializer(ClassReflector|string $initializerClass): Contain
public function removeInitializer(ClassReflector|string $initializerClass): Container
{
if (! $initializerClass instanceof ClassReflector) {
$initializerClass = new ClassReflector($initializerClass);
if (! isset(self::$classReflectors[$initializerClass])) {
self::$classReflectors[$initializerClass] = new ClassReflector($initializerClass);
}
$initializerClass = self::$classReflectors[$initializerClass];
}

if ($initializerClass->getType()->matches(DynamicInitializer::class)) {
Expand Down Expand Up @@ -323,18 +344,26 @@ public function addDecorator(ClassReflector|string $decoratorClass, ClassReflect

private function resolve(string $className, null|string|UnitEnum $tag = null, mixed ...$params): object
{
$key = $this->resolveTaggedName($className, $tag);

if (isset($this->resolved[$key])) {
return $this->resolved[$key];
}
$instance = $this->resolveDependency($className, $tag, ...$params);

if ($this->decorators[$className] ?? null) {
$instance = $this->resolveDecorator($className, $instance, $tag, ...$params);
}

return $instance;
return $this->resolved[$key] = $instance;
}

private function resolveDependency(string $className, null|string|UnitEnum $tag = null, mixed ...$params): object
{
$class = new ClassReflector($className);
if (! isset(self::$classReflectors[$className])) {
self::$classReflectors[$className] = new ClassReflector($className);
}
$class = self::$classReflectors[$className];

$dependencyName = $this->resolveTaggedName($className, $tag);

Expand Down Expand Up @@ -397,14 +426,21 @@ private function initializerForBuiltin(TypeReflector $target, string $tag): ?Ini

private function initializerForClass(ClassReflector $target, null|string|UnitEnum $tag = null): null|Initializer|DynamicInitializer
{
$key = $this->resolveTaggedName($target->getName(), $tag);

if (array_key_exists($key, $this->initializerCache)) {
return $this->initializerCache[$key];
}

// Initializers themselves can't be initialized,
// otherwise you'd end up with infinite loops
if ($target->getType()->matches(Initializer::class) || $target->getType()->matches(DynamicInitializer::class)) {
return null;
return $this->initializerCache[$key] = null;
}

if ($initializerClass = $this->initializers[$this->resolveTaggedName($target->getName(), $tag)] ?? null) {
return $this->resolve($initializerClass);
$initializer = $this->resolve($initializerClass);
return $this->initializerCache[$key] = $initializer;
}

// Loop through the registered initializers to see if
Expand All @@ -417,15 +453,18 @@ private function initializerForClass(ClassReflector $target, null|string|UnitEnu
continue;
}

return $initializer;
return $this->initializerCache[$key] = $initializer;
}

return null;
return $this->initializerCache[$key] = null;
}

private function autowire(string $className, mixed ...$params): object
{
$classReflector = new ClassReflector($className);
if (! isset(self::$classReflectors[$className])) {
self::$classReflectors[$className] = new ClassReflector($className);
}
$classReflector = self::$classReflectors[$className];

$constructor = $classReflector->getConstructor();

Expand Down Expand Up @@ -645,7 +684,11 @@ private function resolveTaggedName(string $className, null|string|UnitEnum $tag)
private function resolveDecorator(string $className, mixed $instance, null|string|UnitEnum $tag = null, mixed ...$params): object
{
foreach ($this->decorators[$className] ?? [] as $decoratorClass) {
$decoratorClassReflector = new ClassReflector($decoratorClass);
if (! isset(self::$classReflectors[$decoratorClass])) {
self::$classReflectors[$decoratorClass] = new ClassReflector($decoratorClass);
}
$decoratorClassReflector = self::$classReflectors[$decoratorClass];

$constructor = $decoratorClassReflector->getConstructor();
$parameters = $constructor?->getParameters();

Expand Down