koded/container is an OOP application bootstrapping and wiring library.
In other words, Koded\DIContainer implements a design pattern called Dependency Inversion.
The main principle of DIP is to separate the behavior from dependency resolution.
composer require koded/containerLet's look at a blog application that has
- interfaces for the database repositories and corresponding implementations
- a shared PDO instance
- a service class for the blog content fetching
- a handler class that maps the request method
usePDO;
interface PostRepository {
publicfunctionfindBySlug(string$slug);
}
interface UserRepository {
publicfunctionfindById(int$id);
}
class DatabasePostRepository implements PostRepository {
private$pdo;
publicfunction__construct(PDO$pdo) {
$this->pdo = $pdo;
}
publicfunctionfindBySlug(string$slug) {
// $this->pdo ...
}
}
class DatabaseUserRepository implements UserRepository {
private$pdo;
publicfunction__construct(PDO$pdo) {
$this->pdo = $pdo;
}
publicfunctionfindById(int$id) {
// $this->pdo ...
}
}Somewhere we may have a service class that uses the dependent repositories:
class PostService {
private$post, $user;
publicfunction__construct(PostRepository$post, UserRepository$user) {
$this->post = $post;
$this->user = $user;
}
// a service method that uses the post and user repository instancespublicfunctionfindBlogPostBySlug(string$slug) {
$post = $this->post->findBySlug($slug);
$user = $this->user->findById($post->userId());
// ... do something with the results, create a result data structure...
}
}Then somewhere we might have a handler/controller that asks for its own dependencies:
class BlogHandler {
publicfunctionget(ServerRequestInterface$request, PostService$service): ResponseInterface {
$slug = slugify($request->getUri()->getPath());
$post = $service->findBlogPostBySlug($slug);
// some PSR-7 compatible response objectreturnnewServerResponse($post);
}
}This is the bootstrapping / wiring application module (or container's "configuration" class) where all known dependencies are binded and shared
class BlogModule implements DIModule {
publicfunctionconfigure(DIContainer$container): void {
// bind interfaces to concrete class implementations$container->bind(PostRepository::class, DatabasePostRepository::class);
$container->bind(UserRepository::class, DatabaseUserRepository::class);
$container->bind(ServerRequestInterface::class, /*some PSR-7 server request class name*/);
// share one PDO instance$container->singleton(PDO::class, ['sqlite:database.db']);
}
}And finally in the dispatcher file, we process the request
// index.php// (resolved through an HTTP router or other means)$handler = BlogHandler::class;
$method = 'get';
// by invoking the container$response = (newDIContainer(newBlogModule))([$handler, $method]);
// we have a `$response` object to output the content// ex. `echo $response->getBody()->getContents();`The container implements the __invoke() method, so the instance can be used as a function:
$container('method', ['arg1', 'arg2', ...]);To be continued...
vendor/bin/infection --threads=4
vendor/bin/phpbench run --report=default
vendor/bin/phpunitThe code is distributed under the terms of The 3-Clause BSD license.

