Skip to content

Commit

Permalink
Fix bug when $container->get('not-existing-service') returns string…
Browse files Browse the repository at this point in the history
… 'not-existing-service' instead of ContainerNotFoundException::class message.

- Uncommented tests
  • Loading branch information
renakdup committed Nov 28, 2023
1 parent cb90b32 commit 0312513
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 49 deletions.
98 changes: 56 additions & 42 deletions src/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,77 +75,91 @@ interface NotFoundExceptionInterface extends ContainerExceptionInterface {}
class Container implements ContainerInterface {
protected array $services = [];

protected array $resolved_services = [];
protected array $resolved = [];

public function set( string $id, $service ): void {
$this->services[ $id ] = $service;
unset( $this->resolved_services[ $id ] );
unset( $this->resolved[ $id ] );
}

/**
* {@inheritdoc}
*/
public function get( string $id ) {
if ( isset( $this->resolved_services[ $id ] ) || array_key_exists( $id, $this->resolved_services ) ) {
return $this->resolved_services[ $id ];
if ( isset( $this->resolved[ $id ] ) || array_key_exists( $id, $this->resolved ) ) {
return $this->resolved[ $id ];
}

$resolved_service = $this->resolve_service( $this->has( $id ) ? $this->services[ $id ] : $id );
$service = $this->resolve( $id );

$this->resolved_services[ $id ] = $resolved_service;
$this->resolved[ $id ] = $service;

return $resolved_service;
return $service;
}

protected function resolve_service( $service ) {
if ( $service instanceof Closure ) {
return $service( $this );
} elseif ( is_object( $service ) ) {
return $service;
} elseif ( is_string( $service ) && class_exists( $service ) ) {
$reflected_class = new ReflectionClass( $service );
$constructor = $reflected_class->getConstructor();

if ( ! $constructor ) {
return new $service();
protected function resolve( $id ) {
if ( $this->has( $id ) ) {
$service = $this->services[ $id ];

if ( $service instanceof Closure ) {
return $service( $this );
} elseif ( is_string( $service ) && class_exists( $service ) ) {
return $this->resolve_object( $service );
} elseif ( is_scalar( $service ) || is_array( $service ) || $service === null ) {
return $service;
} elseif ( is_object( $service ) ) {
return $service;
}

$params = $constructor->getParameters();

if ( ! $params ) {
return new $service();
throw new ContainerNotFoundException( "Service '{$service}' not found in the Container." );
} else {
if ( is_string( $id ) && class_exists( $id ) ) {
return $this->resolve_object( $id );
}

$constructor_args = [];
foreach ( $params as $param ) {
if ( $param_class = $param->getClass() ) {
if ( $this->has( $param_class->getName() ) ) {
$constructor_args[] = $this->get( $param_class->getName() );
continue;
}
throw new ContainerNotFoundException( "Service '{$id}' not found in the Container." );
}
}

protected function resolve_object( $service ) {
$reflected_class = new ReflectionClass( $service );
$constructor = $reflected_class->getConstructor();

if ( ! $constructor ) {
return new $service();
}

$params = $constructor->getParameters();

if ( ! $params ) {
return new $service();
}

$constructor_args = [];
foreach ( $params as $param ) {
if ( $param_class = $param->getClass() ) {
if ( $this->has( $param_class->getName() ) ) {
$constructor_args[] = $this->get( $param_class->getName() );
continue;
}

try {
$default_value = $param->getDefaultValue();
if ( ! $default_value && $default_value !== null ) {
throw new ContainerException( 'Service "' . $reflected_class->getName() . '" could not be resolved due constructor parameter "' . $param->getName() . '"' );
}
} catch ( \ReflectionException $e ) {
throw new ContainerException( 'Service "' . $reflected_class->getName() . '" could not be resolved because parameter of constructor "' . $param . '" has the Reflection issue while resolving: ' . $e->getMessage() );
}
$constructor_args[] = $this->get( $param_class->getName() );
continue;
}

$constructor_args[] = $default_value;
try {
$default_value = $param->getDefaultValue();
if ( ! $default_value && $default_value !== null ) {
throw new ContainerException( 'Service "' . $reflected_class->getName() . '" could not be resolved due constructor parameter "' . $param->getName() . '"' );
}
} catch ( \ReflectionException $e ) {
throw new ContainerException( 'Service "' . $reflected_class->getName() . '" could not be resolved because parameter of constructor "' . $param . '" has the Reflection issue while resolving: ' . $e->getMessage() );
}

return new $service( ...$constructor_args );
} elseif ( is_scalar( $service ) || is_array( $service ) || $service === null ) {
return $service;
$constructor_args[] = $default_value;
}

throw new ContainerNotFoundException( "Service '{$service}' not found in the ServiceContainer." );
return new $service( ...$constructor_args );
}

/**
Expand Down
14 changes: 7 additions & 7 deletions tests/ContainerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -171,16 +171,16 @@ public function test_get__autowiring_for_not_bound_class() {
self::assertEquals( $obj3, $this->container->get( ClassWithConstructor::class ) );
}

// public function test_get__bind_autowiring_container_not_found_exception_string() {
// self::expectException( ServiceContainerNotFoundException::class );
//
// $this->container->get( 'not-exist-service' );
// }
public function test_get__exception_not_found() {
self::expectException( ContainerNotFoundException::class );

$this->container->get( 'not-exist-service' );
}

// public function test_get__bind_autowiring_container_not_found_exception_class() {
// self::expectException( ServiceContainerNotFoundException::class );
// self::expectException( ContainerNotFoundException::class );
//
// $this->container->get( \stdClass::class );
// $this->container->get( SimpleClass::class );
// }

public function test_get__autowiring__container_exception() {
Expand Down

0 comments on commit 0312513

Please sign in to comment.