Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
8aca1aa
Update src/DIContainer.php.
gitauto-ai[bot] Oct 25, 2024
9568370
Update tests/DIContainerTest.php.
gitauto-ai[bot] Oct 25, 2024
9cb19e5
Update docs/DIContainer.md.
gitauto-ai[bot] Oct 25, 2024
5e8725c
Update README.md.
gitauto-ai[bot] Oct 25, 2024
d37137d
style: format code with PHP CS Fixer
deepsource-autofix[bot] Oct 25, 2024
ecba022
Merge branch 'main' into gitauto/issue-237-89757ae2-5736-4b2e-9a82-20…
guibranco Oct 25, 2024
3f4e0a4
Merge branch 'main' into gitauto/issue-237-89757ae2-5736-4b2e-9a82-20…
guibranco Nov 17, 2024
6b1bc25
Merge branch 'main' into gitauto/issue-237-89757ae2-5736-4b2e-9a82-20…
guibranco Jan 6, 2025
6bc07a7
Merge branch 'main' into gitauto/issue-237-89757ae2-5736-4b2e-9a82-20…
guibranco May 14, 2025
80944da
Merge branch 'main' into gitauto/issue-237-89757ae2-5736-4b2e-9a82-20…
guibranco May 27, 2025
9ee215a
Merge branch 'main' into gitauto/issue-237-89757ae2-5736-4b2e-9a82-20…
guibranco Jun 22, 2025
9ab53ce
Merge branch 'main' into gitauto/issue-237-89757ae2-5736-4b2e-9a82-20…
guibranco Jul 11, 2025
31de321
Merge branch 'main' into gitauto/issue-237-89757ae2-5736-4b2e-9a82-20…
guibranco Jul 13, 2025
d70f362
Merge branch 'main' into gitauto/issue-237-89757ae2-5736-4b2e-9a82-20…
guibranco Jul 14, 2025
8a7e57b
Merge branch 'main' into gitauto/issue-237-89757ae2-5736-4b2e-9a82-20…
guibranco Jul 29, 2025
5521cb6
Merge branch 'main' into gitauto/issue-237-89757ae2-5736-4b2e-9a82-20…
gstraccini[bot] Aug 7, 2025
f4db55b
Merge branch 'main' into gitauto/issue-237-89757ae2-5736-4b2e-9a82-20…
gstraccini[bot] Aug 29, 2025
15edcc7
Merge branch 'main' into gitauto/issue-237-89757ae2-5736-4b2e-9a82-20…
gstraccini[bot] Sep 3, 2025
dc1b948
Merge branch 'main' into gitauto/issue-237-89757ae2-5736-4b2e-9a82-20…
guibranco Nov 21, 2025
d40498f
Merge branch 'main' into gitauto/issue-237-89757ae2-5736-4b2e-9a82-20…
guibranco Dec 4, 2025
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
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@

Documentation: [Read the Docs](https://guibranco.github.io/pancake/)

## Features

- Simplified service management with auto-registration.
- Automatic resolution of complex dependency graphs.
- Configurable options to enable or disable auto-registration.

For more details, refer to the [DIContainer Documentation](docs/DIContainer.md).


Check warning

Code scanning / Markdownlint (reported by Codacy)

Expected: 1; Actual: 3 Warning

Expected: 1; Actual: 3

Check warning

Code scanning / Markdownlint (reported by Codacy)

Expected: 1; Actual: 2 Warning

Expected: 1; Actual: 2
---

## Table of contents
Expand Down
63 changes: 63 additions & 0 deletions docs/DIContainer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# DIContainer Documentation

The `DIContainer` class provides a simple and flexible Dependency Injection (DI) Container with auto-registration and automatic dependency resolution features.

## Features

- **Auto-Registration**: Automatically registers services that are not explicitly registered.
- **Automatic Dependency Resolution**: Resolves all dependencies, including constructor dependencies, recursively.
- **Configurable**: Auto-registration can be enabled or disabled as needed.

## Usage

### Enabling Auto-Registration

By default, auto-registration is enabled. You can create a `DIContainer` instance and resolve services without explicit registration:

```php
$container = new DIContainer();
$service = $container->resolve(MyService::class);
```

### Disabling Auto-Registration

To disable auto-registration, pass `false` to the constructor:

```php
$container = new DIContainer(false);
```

### Registering Services Explicitly

You can still register services explicitly using `registerSingleton` or `registerTransient`:

```php
$container->registerSingleton(MyService::class, new MyService());
$container->registerTransient(MyOtherService::class, function() {
return new MyOtherService();
});
```

### Handling Dependencies

The container automatically resolves dependencies for services with constructor arguments:

```php
class MyService {
public function __construct(Dependency $dependency) {}
}

$service = $container->resolve(MyService::class);
```

## Exception Handling

If a service cannot be resolved, an exception is thrown with a clear message:

- **Service Not Found**: When auto-registration is disabled and a service is not registered.
- **Cannot Resolve Dependency**: When a dependency cannot be resolved due to missing type hints or non-existent classes.

## Considerations

- Explicitly registered services take precedence over auto-registered services.
- Ensure that all dependencies have appropriate type hints for successful resolution.
67 changes: 67 additions & 0 deletions src/DIContainer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

class DIContainer
{
private $services = [];

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 1 blank line(s) before first member var; 0 found Warning

Expected 1 blank line(s) before first member var; 0 found

Check warning

Code scanning / Phpcs (reported by Codacy)

Missing member variable doc comment Warning

Missing member variable doc comment
private $autoRegisterEnabled = true;

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 1 blank line(s) before member var; 0 found Warning

Expected 1 blank line(s) before member var; 0 found

Check warning

Code scanning / Phpcs (reported by Codacy)

Missing member variable doc comment Warning

Missing member variable doc comment

public function __construct($autoRegisterEnabled = true)

Check warning

Code scanning / Phpcs (reported by Codacy)

Incorrect spacing between default value and equals sign for argument "$autoRegisterEnabled"; expected 0 but found 1 Warning

Incorrect spacing between default value and equals sign for argument "$autoRegisterEnabled"; expected 0 but found 1

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 2 blank lines before function; 1 found Warning

Expected 2 blank lines before function; 1 found

Check warning

Code scanning / Phpcs (reported by Codacy)

Missing doc comment for function __construct() Warning

Missing doc comment for function __construct()

Check warning

Code scanning / Phpcs (reported by Codacy)

Incorrect spacing between argument "$autoRegisterEnabled" and equals sign; expected 0 but found 1 Warning

Incorrect spacing between argument "$autoRegisterEnabled" and equals sign; expected 0 but found 1
{
$this->autoRegisterEnabled = $autoRegisterEnabled;
}

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 2 blank lines after function; 1 found Warning

Expected 2 blank lines after function; 1 found

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 1 blank line before closing function brace; 0 found Warning

Expected 1 blank line before closing function brace; 0 found

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected //end __construct() Warning

Expected //end __construct()

public function resolve($name)

Check warning

Code scanning / Phpcs (reported by Codacy)

Missing doc comment for function resolve() Warning

Missing doc comment for function resolve()
{
if (isset($this->services[$name])) {

Check notice

Code scanning / Phpcs (reported by Codacy)

Implicit true comparisons prohibited; use === TRUE instead Note

Implicit true comparisons prohibited; use === TRUE instead
return $this->services[$name];
}

if ($this->autoRegisterEnabled) {

Check notice

Code scanning / Phpcs (reported by Codacy)

Implicit true comparisons prohibited; use === TRUE instead Note

Implicit true comparisons prohibited; use === TRUE instead
return $this->autoRegister($name);
}

throw new Exception("Service not found: $name");

Check failure

Code scanning / Phpcs (reported by Codacy)

All output should be run through an escaping function (see the Security sections in the WordPress Developer Handbooks), found '"Service not found: $name"'. Error

All output should be run through an escaping function (see the Security sections in the WordPress Developer Handbooks), found '"Service not found: $name"'.
}

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected //end resolve() Warning

Expected //end resolve()

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 2 blank lines after function; 1 found Warning

Expected 2 blank lines after function; 1 found

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 1 blank line before closing function brace; 0 found Warning

Expected 1 blank line before closing function brace; 0 found

private function autoRegister($name)

Check warning

Code scanning / Phpcs (reported by Codacy)

Missing doc comment for function autoRegister() Warning

Missing doc comment for function autoRegister()
{
if (!class_exists($name)) {

Check notice

Code scanning / Phpcs (reported by Codacy)

Operator ! prohibited; use === FALSE instead Note

Operator ! prohibited; use === FALSE instead
throw new Exception("Class not found: $name");

Check failure

Code scanning / Phpcs (reported by Codacy)

All output should be run through an escaping function (see the Security sections in the WordPress Developer Handbooks), found '"Class not found: $name"'. Error

All output should be run through an escaping function (see the Security sections in the WordPress Developer Handbooks), found '"Class not found: $name"'.
}

$reflectionClass = new ReflectionClass($name);
$constructor = $reflectionClass->getConstructor();

if (is_null($constructor)) {

Check failure

Code scanning / Phpcs (reported by Codacy)

The use of function is_null() is discouraged; use strict comparison "=== null" instead. Error

The use of function is_null() is discouraged; use strict comparison "=== null" instead.

Check notice

Code scanning / Phpcs (reported by Codacy)

Implicit true comparisons prohibited; use === TRUE instead Note

Implicit true comparisons prohibited; use === TRUE instead
return new $name();
}

$parameters = $constructor->getParameters();
$dependencies = [];

foreach ($parameters as $parameter) {
$dependencyClass = $parameter->getClass();
if (is_null($dependencyClass)) {

Check failure

Code scanning / Phpcs (reported by Codacy)

The use of function is_null() is discouraged; use strict comparison "=== null" instead. Error

The use of function is_null() is discouraged; use strict comparison "=== null" instead.

Check notice

Code scanning / Phpcs (reported by Codacy)

Implicit true comparisons prohibited; use === TRUE instead Note

Implicit true comparisons prohibited; use === TRUE instead
throw new Exception("Cannot resolve dependency: " . $parameter->getName());

Check failure

Code scanning / Phpcs (reported by Codacy)

All output should be run through an escaping function (see the Security sections in the WordPress Developer Handbooks), found '$parameter'. Error

All output should be run through an escaping function (see the Security sections in the WordPress Developer Handbooks), found '$parameter'.

Check warning

Code scanning / Phpcs (reported by Codacy)

Concat operator must not be surrounded by spaces Warning

Concat operator must not be surrounded by spaces
}

Check warning

Code scanning / Phpcs (reported by Codacy)

No blank line found after control structure Warning

No blank line found after control structure
$dependencies[] = $this->resolve($dependencyClass->getName());
}

return $reflectionClass->newInstanceArgs($dependencies);
}

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected //end autoRegister() Warning

Expected //end autoRegister()

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 1 blank line before closing function brace; 0 found Warning

Expected 1 blank line before closing function brace; 0 found

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 2 blank lines after function; 1 found Warning

Expected 2 blank lines after function; 1 found

public function setAutoRegisterEnabled(bool $enabled)

Check warning

Code scanning / Phpcs (reported by Codacy)

Missing doc comment for function setAutoRegisterEnabled() Warning

Missing doc comment for function setAutoRegisterEnabled()
{
$this->autoRegisterEnabled = $enabled;
}

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 2 blank lines after function; 1 found Warning

Expected 2 blank lines after function; 1 found

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected //end setAutoRegisterEnabled() Warning

Expected //end setAutoRegisterEnabled()

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 1 blank line before closing function brace; 0 found Warning

Expected 1 blank line before closing function brace; 0 found

public function registerSingleton($name, $instance)

Check warning

Code scanning / Phpcs (reported by Codacy)

Missing doc comment for function registerSingleton() Warning

Missing doc comment for function registerSingleton()
{
$this->services[$name] = $instance;
}

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 2 blank lines after function; 1 found Warning

Expected 2 blank lines after function; 1 found

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected //end registerSingleton() Warning

Expected //end registerSingleton()

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 1 blank line before closing function brace; 0 found Warning

Expected 1 blank line before closing function brace; 0 found

public function registerTransient($name, $closure)

Check warning

Code scanning / Phpcs (reported by Codacy)

Missing doc comment for function registerTransient() Warning

Missing doc comment for function registerTransient()
{
$this->services[$name] = $closure();
}

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 1 blank line before closing function brace; 0 found Warning

Expected 1 blank line before closing function brace; 0 found

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected //end registerTransient() Warning

Expected //end registerTransient()

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 2 blank lines after function; 0 found Warning

Expected 2 blank lines after function; 0 found
}

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected //end class Warning

Expected //end class
73 changes: 73 additions & 0 deletions tests/DIContainerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php

use PHPUnit\Framework\TestCase;

class DIContainerTest extends TestCase
{
public function testAutoRegistration()

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 2 blank lines before function; 0 found Warning test

Expected 2 blank lines before function; 0 found

Check warning

Code scanning / Phpcs (reported by Codacy)

Missing doc comment for function testAutoRegistration() Warning test

Missing doc comment for function testAutoRegistration()
{
$container = new DIContainer();
$service = $container->resolve(TestService::class);
$this->assertInstanceOf(TestService::class, $service);
}

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected //end testAutoRegistration() Warning test

Expected //end testAutoRegistration()

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 1 blank line before closing function brace; 0 found Warning test

Expected 1 blank line before closing function brace; 0 found

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 2 blank lines after function; 1 found Warning test

Expected 2 blank lines after function; 1 found

public function testDependencyResolution()

Check warning

Code scanning / Phpcs (reported by Codacy)

Missing doc comment for function testDependencyResolution() Warning test

Missing doc comment for function testDependencyResolution()
{
$container = new DIContainer();
$service = $container->resolve(ServiceWithDependencies::class);
$this->assertInstanceOf(ServiceWithDependencies::class, $service);
$this->assertInstanceOf(Dependency::class, $service->getDependency());
}

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected //end testDependencyResolution() Warning test

Expected //end testDependencyResolution()

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 2 blank lines after function; 1 found Warning test

Expected 2 blank lines after function; 1 found

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 1 blank line before closing function brace; 0 found Warning test

Expected 1 blank line before closing function brace; 0 found

public function testAutoRegistrationDisabled()

Check warning

Code scanning / Phpcs (reported by Codacy)

Missing doc comment for function testAutoRegistrationDisabled() Warning test

Missing doc comment for function testAutoRegistrationDisabled()
{
$this->expectException(Exception::class);
$this->expectExceptionMessage('Service not found: UnregisteredService');

$container = new DIContainer(false);
$container->resolve(UnregisteredService::class);
}

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected //end testAutoRegistrationDisabled() Warning test

Expected //end testAutoRegistrationDisabled()

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 2 blank lines after function; 1 found Warning test

Expected 2 blank lines after function; 1 found

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 1 blank line before closing function brace; 0 found Warning test

Expected 1 blank line before closing function brace; 0 found

public function testExceptionHandlingForUnresolvableDependency()

Check warning

Code scanning / Phpcs (reported by Codacy)

Missing doc comment for function testExceptionHandlingForUnresolvableDependency() Warning test

Missing doc comment for function testExceptionHandlingForUnresolvableDependency()
{
$this->expectException(Exception::class);
$this->expectExceptionMessage('Cannot resolve dependency: unresolvable');

$container = new DIContainer();
$container->resolve(ServiceWithUnresolvableDependency::class);
}

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 1 blank line before closing function brace; 0 found Warning test

Expected 1 blank line before closing function brace; 0 found

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 2 blank lines after function; 0 found Warning test

Expected 2 blank lines after function; 0 found

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected //end testExceptionHandlingForUnresolvableDependency() Warning test

Expected //end testExceptionHandlingForUnresolvableDependency()
}

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected //end class Warning test

Expected //end class

class TestService
{
}

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected //end class Warning test

Expected //end class

class Dependency
{
}

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected //end class Warning test

Expected //end class

class ServiceWithDependencies
{
private $dependency;

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 1 blank line(s) before first member var; 0 found Warning test

Expected 1 blank line(s) before first member var; 0 found

Check warning

Code scanning / Phpcs (reported by Codacy)

Missing member variable doc comment Warning test

Missing member variable doc comment

public function __construct(Dependency $dependency)

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 2 blank lines before function; 1 found Warning test

Expected 2 blank lines before function; 1 found

Check warning

Code scanning / Phpcs (reported by Codacy)

Missing doc comment for function __construct() Warning test

Missing doc comment for function __construct()
{
$this->dependency = $dependency;
}

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 2 blank lines after function; 1 found Warning test

Expected 2 blank lines after function; 1 found

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected //end __construct() Warning test

Expected //end __construct()

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 1 blank line before closing function brace; 0 found Warning test

Expected 1 blank line before closing function brace; 0 found

public function getDependency()

Check warning

Code scanning / Phpcs (reported by Codacy)

Missing doc comment for function getDependency() Warning test

Missing doc comment for function getDependency()
{
return $this->dependency;
}

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected //end getDependency() Warning test

Expected //end getDependency()

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 1 blank line before closing function brace; 0 found Warning test

Expected 1 blank line before closing function brace; 0 found

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 2 blank lines after function; 0 found Warning test

Expected 2 blank lines after function; 0 found
}

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected //end class Warning test

Expected //end class

class UnregisteredService
{
}

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected //end class Warning test

Expected //end class

class ServiceWithUnresolvableDependency
{
public function __construct($unresolvable)

Check warning

Code scanning / Phpcs (reported by Codacy)

Missing doc comment for function __construct() Warning test

Missing doc comment for function __construct()

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 2 blank lines before function; 0 found Warning test

Expected 2 blank lines before function; 0 found

Check notice

Code scanning / Phpmd (reported by Codacy)

This rule prohibits the definition of unused parameters in methods or constructors. Note test

Avoid unused parameters such as '$unresolvable'.
{
}

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 2 blank lines after function; 0 found Warning test

Expected 2 blank lines after function; 0 found

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected //end __construct() Warning test

Expected //end __construct()

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected 1 blank line before closing function brace; 0 found Warning test

Expected 1 blank line before closing function brace; 0 found
}

Check warning

Code scanning / Phpcs (reported by Codacy)

Expected //end class Warning test

Expected //end class
Loading