diff --git a/src/Adapter/ArrayContainerAdapter.php b/src/Adapter/ArrayContainerAdapter.php index be05a2e..b3b53cc 100644 --- a/src/Adapter/ArrayContainerAdapter.php +++ b/src/Adapter/ArrayContainerAdapter.php @@ -17,6 +17,8 @@ class ArrayContainerAdapter implements ContainerInterface */ private $arrayContainer; + private bool $useOptimizedLookup; + /** * ArrayContainerAdapter constructor. * @param array|\ArrayAccess $arrayContainer @@ -24,6 +26,7 @@ class ArrayContainerAdapter implements ContainerInterface public function __construct($arrayContainer) { $this->arrayContainer = $arrayContainer; + $this->useOptimizedLookup = is_object($arrayContainer) && method_exists($arrayContainer, 'getIfDefined'); } /** @@ -38,12 +41,41 @@ public function __construct($arrayContainer) */ public function get($id) { + if ($this->useOptimizedLookup) { + try { + return $this->arrayContainer[$id]; + } catch (\InvalidArgumentException $e) { + throw new ServiceNotFoundException("Service not found in container ($id).", 0, $e); + } + } if (!isset($this->arrayContainer[$id])) { throw new ServiceNotFoundException("Service not found in container ($id)."); } return $this->arrayContainer[$id]; } + /** + * Check if the entry exists and retrieve it in a single operation. + * Avoids the double container lookup of separate has() + get() calls. + * When the underlying container supports getIfDefined (e.g. JITContainer), + * this reduces provider loading from 3 calls to 1. + * + * @param string $id Identifier of the entry to look for. + * @param mixed $result Will be set to the entry value if found. + * @return bool True if the entry was found. + */ + public function getIfDefined(string $id, mixed &$result): bool + { + if ($this->useOptimizedLookup) { + return $this->arrayContainer->getIfDefined($id, $result); + } + if (!isset($this->arrayContainer[$id])) { + return false; + } + $result = $this->arrayContainer[$id]; + return true; + } + /** * Returns true if the container can return an entry for the given identifier. * Returns false otherwise. diff --git a/src/Injector.php b/src/Injector.php index fa2f5c1..6eb273c 100644 --- a/src/Injector.php +++ b/src/Injector.php @@ -43,8 +43,11 @@ class Injector implements InjectorInterface */ private array $autoCreateCache = []; + private readonly bool $hasGetIfDefined; + public function __construct(private readonly ContainerInterface $container, private readonly ClassInspectorInterface $classInspector) { + $this->hasGetIfDefined = method_exists($container, 'getIfDefined'); } /** @@ -237,15 +240,22 @@ private function buildParameterArray($methodSignature, $providedParameters) private function buildParameterArrayFromContainer($methodSignature) { $parameters = []; + $container = $this->container; + $useOptimized = $this->hasGetIfDefined; foreach ($methodSignature as $position => $parameterData) { if (isset($parameterData['variadic'])) { - // variadic with no provided params = nothing to pipe break; } $type = $parameterData['type'] ?? false; if ($type) { - if ($this->container->has($type)) { - $parameters[$position] = $this->container->get($type); + if ($useOptimized) { + $value = null; + if ($container->getIfDefined($type, $value)) { + $parameters[$position] = $value; + continue; + } + } elseif ($container->has($type)) { + $parameters[$position] = $container->get($type); continue; } if ($this->canAutoCreate($type)) { diff --git a/src/Reflection/CachingClassInspector.php b/src/Reflection/CachingClassInspector.php index 3e33937..8937d99 100644 --- a/src/Reflection/CachingClassInspector.php +++ b/src/Reflection/CachingClassInspector.php @@ -14,6 +14,11 @@ class CachingClassInspector implements ClassInspectorInterface */ private array $constructorCache = []; + /** + * @var array + */ + private array $methodSignatureCache = []; + public function __construct( private readonly ClassInspector $classInspector, private readonly ServiceCacheInterface $serviceCache, @@ -93,6 +98,11 @@ public function methodIsPublic(string $class, string $method): bool */ public function getMethodSignature(string $class, string $method): array { + $cacheKey = "$class::$method"; + if (isset($this->methodSignatureCache[$cacheKey])) { + return $this->methodSignatureCache[$cacheKey]; + } + $key = "$class::{$method}::signature"; if ($this->serviceCache->has($key)) { $value = $this->serviceCache->get($key); @@ -101,6 +111,7 @@ public function getMethodSignature(string $class, string $method): array $this->serviceCache->set($key, $value); } + $this->methodSignatureCache[$cacheKey] = $value; return $value; }