Sounds exciting, doesn't it?! Well this is aimed to be a simple container that can help you prevent dependency-hell.
// Map interfaces to concrete classes.
$dependencyMap = [
MyDependencyInterface::class => MyDependencyPort::class
];
// Pass them to the container.
$container = new Container($dependencyMap);
// Annotate your classes with #[Injected] on properties or constructor params.
class Main
{
#[Injected]
protected MyDependencyInterface $dependency;
protected MyOtherDependencyInterface $otherDependency;
public function __construct(MyOtherDependencyInterface $otherDependency)
{
$this->otherDependency = $otherDependency;
}
}
$main = $container->make(Main::class);
// Now the dependency will be fulfilled, and you can call methods that rely
// on them.
$main->whateverMethod();
Say you've got a dependency that you'd like to bring in from some third party, what you really should do, is write an interface for the methods you need, and a port that interacts with the dependency. This way the third party dependency is isolated to a single port, and doesn't pollute it's way throughout your code.
The way that this project is meant to be used, is first to require it in your project:
$ composer require fowlerwill/attribute-injection
Then, you can instantiate the Container, and provide it with your interface map that maps the dependencies to ports.
// Somewhere like index.php or during bootstrap of your application.
$dependencyMap = [
MyDependencyInterface::class => MyDependencyPort::class
];
$container = new Container($dependencyMap);
Where MyDependencyInterface.php
might look like this:
interface MyDependencyInterface
{
public function party(): string;
}
and MyDependencyPort.php
might looks like this:
use FowlerWill\AttributeInjection\Injected;
use Thirdparty\Dependency\SomeDependency;
class MyDependencyPort implements MyDependencyInterface
{
#[Injected]
protected SomeDependency $dependency;
public function party(): string
{
return "party, " . $this->dependency->partyHard();
}
}
Notice that we've used the PHP Attribute #[Injected]
there to bring the
dependency along for the ride, when we tie it all together with our class that
uses the interface...
use FowlerWill\AttributeInjection\Injected;
class Main
{
#[Injected]
protected MyDependencyInterface $dependency;
public function itsTimeToParty(): string
{
return "I believe it's time to ".$this->dependency->party();
}
}
and back in our application, we instantiate the class via the container, and can use the dependencies that have been provided to the properites in the class.
$main = $container->make(Main::class);
echo $main->itsTimeToParty();
First, I'm honoured that you'd want to contribute to the project, so thank you for even considering. There are a lot of ideas that I have for the project, but am super open to PR's at this stage to help grow into use cases that you need.
$ composer install
To run the tests locally:
$ composer run test
To run the tests on docker, with coverage report:
$ composer run test-docker