Created
January 21, 2025 22:14
-
-
Save diloabininyeri/2c8a9d8e5a43a1211fa8729a0bb7b634 to your computer and use it in GitHub Desktop.
php conxtual container
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class Container | |
{ | |
/** | |
* @var array | |
*/ | |
private array $bindings = []; | |
/** | |
* @var array | |
*/ | |
private array $context = []; | |
/** | |
* @param string $name | |
* @param callable|string $concrete | |
* @return void | |
*/ | |
public function bind(string $name, callable|string $concrete): void | |
{ | |
if (!is_callable($concrete)) { | |
$concrete = static fn(Container $container) => $container->resolve($concrete); | |
} | |
$this->bindings[$name] = $concrete; | |
} | |
/** | |
* @param string $name | |
* @return mixed | |
* @throws ReflectionException | |
*/ | |
public function make(string $name): mixed | |
{ | |
if (!$this->has($name)) { | |
return $this->resolve($name); | |
} | |
return $this->bindings[$name]($this); | |
} | |
/** | |
* @param string $name | |
* @return bool | |
*/ | |
public function has(string $name): bool | |
{ | |
return isset($this->bindings[$name]); | |
} | |
/** | |
* @param string $scope | |
* @param string $implementation | |
* @param string $concrete | |
* @return void | |
*/ | |
public function addContext(string $scope, string $implementation, string $concrete): void | |
{ | |
$this->context[$scope][$implementation] = static fn(Container $container) => $container->resolve($concrete); | |
} | |
/*** | |
* @param string $class | |
* @return object | |
* @throws ReflectionException | |
*/ | |
public function resolve(string $class): object | |
{ | |
$reflectionClass = new ReflectionClass($class); | |
$constructor = $reflectionClass->getConstructor(); | |
if ($constructor === null) { | |
return new $class(); | |
} | |
return $reflectionClass->newInstanceArgs( | |
array_map( | |
fn(ReflectionParameter $parameter) => $this->resolveParameter($parameter, $class), | |
$constructor->getParameters() | |
) | |
); | |
} | |
/** | |
* @param string $class | |
* @param string $interface | |
* @return bool | |
*/ | |
private function hasContext(string $class, string $interface): bool | |
{ | |
return isset($this->context[$class][$interface]); | |
} | |
/** | |
* @param string $class | |
* @param string $interface | |
* @return callable | |
*/ | |
private function getContext(string $class, string $interface): callable | |
{ | |
return $this->context[$class][$interface]; | |
} | |
/** | |
* @param ReflectionParameter $parameter | |
* @param string $class | |
* @return mixed | |
* @throws ReflectionException | |
*/ | |
private function resolveParameter(ReflectionParameter $parameter, string $class): mixed | |
{ | |
$interface = $parameter->getType()?->getName(); | |
if ($this->hasContext($class, $interface)) { | |
return $this->getContext($class, $interface)($this); | |
} | |
return $this->make($interface); | |
} | |
} | |
/** | |
* | |
*/ | |
class User implements UserInterface | |
{ | |
} | |
/** | |
* | |
*/ | |
interface UserInterface | |
{ | |
} | |
/** | |
* | |
*/ | |
class Book implements BookInterface | |
{ | |
/** | |
* @param UserInterface $user | |
*/ | |
public function __construct(private UserInterface $user) | |
{ | |
} | |
} | |
/** | |
* | |
*/ | |
interface BookInterface | |
{ | |
} | |
/** | |
* | |
*/ | |
class Author | |
{ | |
/** | |
* @param BookInterface $book | |
*/ | |
public function __construct(private BookInterface $book) | |
{ | |
} | |
} | |
/** | |
* | |
*/ | |
interface LoggerInterface | |
{ | |
/** | |
* @return void | |
*/ | |
public function log(): void; | |
} | |
/** | |
* | |
*/ | |
class FileLogger implements LoggerInterface | |
{ | |
/** | |
* @return void | |
*/ | |
public function log(): void | |
{ | |
echo __CLASS__ . PHP_EOL; | |
} | |
} | |
/** | |
* | |
*/ | |
class DatabaseLogger implements LoggerInterface | |
{ | |
/** | |
* @return void | |
*/ | |
public function log(): void | |
{ | |
echo __CLASS__ . PHP_EOL; | |
} | |
} | |
/** | |
* | |
*/ | |
readonly class PhpBook | |
{ | |
/** | |
* @param LoggerInterface $logger | |
* @param UserInterface $user | |
*/ | |
public function __construct(private LoggerInterface $logger, private UserInterface $user) | |
{ | |
$this->logger->log(); | |
var_dump($this->user); | |
} | |
} | |
/** | |
* | |
*/ | |
class Test | |
{ | |
/** | |
* @param LoggerInterface $logger | |
*/ | |
public function __construct(private LoggerInterface $logger) | |
{ | |
$this->logger->log(); | |
} | |
} | |
$container = new Container(); | |
$container->bind(UserInterface::class, User::class); | |
$container->bind(BookInterface::class, Book::class); | |
$container->bind(LoggerInterface::class, FileLogger::class); | |
$container->addContext(PhpBook::class, LoggerInterface::class, DatabaseLogger::class); | |
$container->addContext(Test::class, LoggerInterface::class, FileLogger::class); | |
$book = $container->make(PhpBook::class); | |
$test = $container->make(Test::class); | |
var_dump($book); | |
var_dump($test); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment