Skip to content
Merged
Show file tree
Hide file tree
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
28 changes: 28 additions & 0 deletions src/Di/Di.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,34 @@ public static function isRegistered(string $abstract): bool
return isset(self::$dependencies[$abstract]);
}

/**
* Sets an instance into container
* @param string $abstract
* @param object $instance
* @return void
* @throws DiException
*/
public static function set(string $abstract, object $instance): void
{
if (!class_exists($abstract) && !interface_exists($abstract)) {
throw DiException::invalidAbstractDependency($abstract);
}

if (!is_a($instance, $abstract)) {
throw DiException::invalidAbstractDependency($abstract);
}

if (isset(self::$container[$abstract])) {
throw DiException::dependencyAlreadyRegistered($abstract);
}

if (!isset(self::$dependencies[$abstract])) {
self::$dependencies[$abstract] = get_class($instance);
}

self::$container[$abstract] = $instance;
}

/**
* Retrieves a shared instance of the given dependency.
* @param string $dependency
Expand Down
59 changes: 59 additions & 0 deletions tests/Unit/Di/DiTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,65 @@ public function testDiAbstractToConcreteBinding()
$this->assertInstanceOf(DummyService::class, $instance);
}

public function testDiSetBindsInstanceToAbstract(): void
{
$instance = new DummyService();

Di::set(DummyServiceInterface::class, $instance);

$resolved = Di::get(DummyServiceInterface::class);

$this->assertSame($instance, $resolved);
$this->assertInstanceOf(DummyService::class, $resolved);
}

public function testDiSetWorksWithoutPriorRegister(): void
{
$instance = new DummyService();

$this->assertFalse(Di::isRegistered(DummyServiceInterface::class));

Di::set(DummyServiceInterface::class, $instance);

$this->assertTrue(Di::isRegistered(DummyServiceInterface::class));

$this->assertSame($instance, Di::get(DummyServiceInterface::class));
}

public function testDiSetRejectsWrongInstanceType(): void
{
$this->expectException(DiException::class);
$this->expectExceptionMessage(
'The dependency `' . DummyServiceInterface::class . '` is not valid abstract class.'
);

Di::set(DummyServiceInterface::class, new \stdClass());
}

public function testDiSetRejectsInvalidAbstract(): void
{
$this->expectException(DiException::class);
$this->expectExceptionMessage(
'The dependency `NonExistentInterface` is not valid abstract class.'
);

Di::set('NonExistentInterface', new DummyService());
}

public function testDiSetRejectsWhenAlreadyResolved(): void
{
Di::register(DummyService::class);

Di::get(DummyService::class); // resolve singleton first

$this->expectException(DiException::class);
$this->expectExceptionMessage(
'The dependency `' . DummyService::class . '` is already registered.'
);

Di::set(DummyService::class, new DummyService());
}

public function testDiGetCoreDependencies()
{
$this->assertInstanceOf(Loader::class, Di::get(Loader::class));
Expand Down