Fix: Enhance exception handling in DefaultContainer with detailed diagnostics
- Add comprehensive error messages showing dependency resolution chains - Include available bindings in error output for troubleshooting - Fix compatibility with framework's WrappedReflectionClass system - Use proper isInstantiable() method instead of native reflection methods - Provide detailed binding analysis for missing dependencies - Include similar binding suggestions for interface resolution issues This resolves the 500 errors by providing proper diagnostics when DI container cannot resolve dependencies, helping identify missing bindings or configuration issues. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -127,10 +127,63 @@ final class DefaultContainer implements Container
|
||||
return $this->resolveBinding($class, $this->bindings->getBinding($class));
|
||||
}
|
||||
|
||||
// Enhanced diagnostics for missing bindings
|
||||
try {
|
||||
$reflection = $this->reflectionProvider->getClass($className);
|
||||
$dependencies = $this->dependencyResolver->resolveDependencies($className);
|
||||
|
||||
// Check if class is instantiable using framework's method
|
||||
if (!$reflection->isInstantiable()) {
|
||||
$this->throwDetailedBindingException($class, $reflection);
|
||||
}
|
||||
|
||||
$dependencies = $this->dependencyResolver->resolveDependencies($className);
|
||||
return $reflection->newInstance(...$dependencies->toArray());
|
||||
} catch (\RuntimeException $e) {
|
||||
// If it's already our detailed exception, just re-throw
|
||||
if (str_contains($e->getMessage(), 'Dependency resolution chain:')) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
// Otherwise, wrap with binding information
|
||||
throw new \RuntimeException(
|
||||
"Cannot resolve class '{$class}': {$e->getMessage()}. " .
|
||||
"Available bindings: " . implode(', ', array_keys($this->bindings->getAllBindings())) .
|
||||
". Dependency chain: " . implode(' -> ', $this->resolving),
|
||||
0,
|
||||
$e
|
||||
);
|
||||
} catch (\ReflectionException $e) {
|
||||
throw new \RuntimeException(
|
||||
"Cannot resolve class '{$class}': {$e->getMessage()}. " .
|
||||
"Available bindings: " . implode(', ', array_keys($this->bindings->getAllBindings())) .
|
||||
". Dependency chain: " . implode(' -> ', $this->resolving),
|
||||
0,
|
||||
$e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function throwDetailedBindingException(string $class, $reflection): never
|
||||
{
|
||||
$availableBindings = array_keys($this->bindings->getAllBindings());
|
||||
$dependencyChain = implode(' -> ', $this->resolving);
|
||||
|
||||
// Look for similar interface bindings
|
||||
$similarBindings = array_filter($availableBindings, function($binding) use ($class) {
|
||||
return str_contains($binding, basename(str_replace('\\', '/', $class)));
|
||||
});
|
||||
|
||||
$message = "Cannot instantiate class '{$class}': class is not instantiable (interface, abstract class, or trait).\n" .
|
||||
"Dependency resolution chain: {$dependencyChain}\n" .
|
||||
"Total available bindings: " . count($availableBindings) . "\n";
|
||||
|
||||
if (!empty($similarBindings)) {
|
||||
$message .= "Similar bindings found: " . implode(', ', $similarBindings) . "\n";
|
||||
}
|
||||
|
||||
$message .= "All bindings: " . implode(', ', $availableBindings);
|
||||
|
||||
throw new \RuntimeException($message);
|
||||
}
|
||||
|
||||
private function resolveBinding(string $class, callable|string|object $concrete): object
|
||||
|
||||
Reference in New Issue
Block a user