*/ public function listBindings(): array { return array_keys($this->bindings->getAllBindings()); } public function getBinding(string $abstract): callable|string|object|null { return $this->bindings->getBinding($abstract); } /** * @return array */ public function listSingletons(): array { return $this->instances->getSingletons(); } /** * @return array */ public function listInstances(): array { return $this->instances->getInstanceKeys(); } /** @param class-string $class */ public function isSingleton(string $class): bool { return $this->instances->isMarkedAsSingleton($class) || $this->instances->hasSingleton($class); } /** * @return array */ public function getResolutionChain(): array { $f = $this->resolutionChainProvider; /** @var array $chain */ $chain = $f(); return $chain; } /** @param class-string $class */ public function isInstantiable(string $class): bool { if ($class === '') { return false; } $className = ClassName::create($class); if (! $className->exists()) { return false; } return $this->reflectionProvider->getClass($className)->isInstantiable(); } /** * Describe resolution state and constructor parameters for diagnostics. * @param class-string $class * @return array */ public function describe(string $class): array { $className = ClassName::create($class); $exists = $className->exists(); $hasBinding = $this->bindings->hasBinding($class); $hasInstance = $this->instances->hasInstance($class) || $this->instances->hasSingleton($class); $singletonMarked = $this->instances->isMarkedAsSingleton($class); $instantiable = false; $constructor = [ 'has_constructor' => false, 'parameters' => [], ]; $binding = $this->bindings->getBinding($class); $bindingType = null; if ($binding !== null) { $bindingType = is_callable($binding) ? 'callable' : (is_string($binding) ? 'string' : 'object'); } if ($exists) { try { $reflection = $this->reflectionProvider->getClass($className); $instantiable = $reflection->isInstantiable(); if ($reflection->hasMethod('__construct')) { $ctor = $reflection->getConstructor(); if ($ctor !== null) { $constructor['has_constructor'] = true; foreach ($ctor->getParameters() as $param) { $type = $param->getType(); $typeName = null; $isBuiltin = false; if ($type instanceof \ReflectionNamedType) { $typeName = $type->getName(); $isBuiltin = $type->isBuiltin(); } elseif ($type !== null) { // union or complex type - string cast $typeName = (string) $type; } $resolvable = true; if ($typeName !== null && ! $isBuiltin) { // best-effort check for class/interface $resolvable = $this->container->has($typeName); } $constructor['parameters'][] = [ 'name' => $param->getName(), 'type' => $typeName, 'allows_null' => $type?->allowsNull() ?? true, 'is_builtin' => $isBuiltin, 'has_default' => $param->isDefaultValueAvailable(), 'resolvable' => $resolvable, ]; } } } } catch (\Throwable $e) { // Keep defaults if reflection fails, but include error message for diagnostics. $constructor['error'] = $e->getMessage(); } } $suggestions = []; if (! $exists) { $suggestions[] = 'Class does not exist - check namespace and autoloading.'; } elseif (! $instantiable && ! $hasBinding) { $suggestions[] = 'Class is not instantiable - add a binding from interface/abstract to a concrete implementation.'; } if (! $hasBinding && $instantiable && ($constructor['has_constructor'] ?? false)) { foreach ($constructor['parameters'] as $p) { if ($p['type'] && ! $p['is_builtin'] && ! $p['resolvable']) { $suggestions[] = "Add binding for dependency '{$p['type']}' or ensure it is instantiable."; } } } $chain = $this->getResolutionChain(); return [ 'class' => $class, 'exists' => $exists, 'instantiable' => $instantiable, 'has_binding' => $hasBinding, 'binding_type' => $bindingType, 'has_instance' => $hasInstance, 'singleton_marked' => $singletonMarked, 'constructor' => $constructor, 'resolution_chain' => $chain, 'counts' => [ 'bindings' => count($this->bindings->getAllBindings()), 'singletons' => count($this->instances->getSingletons()), 'instances' => count($this->instances->getInstanceKeys()), ], 'suggestions' => array_values(array_unique($suggestions)), ]; } }