Files
kiri-container/Container.php
T

330 lines
6.9 KiB
PHP
Raw Normal View History

2022-01-25 15:35:48 +08:00
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2018/4/24 0024
* Time: 17:27
*/
declare(strict_types=1);
namespace Kiri\Di;
2023-04-15 23:32:00 +08:00
use Psr\Container\ContainerInterface;
2022-01-25 15:35:48 +08:00
use ReflectionClass;
use ReflectionException;
use ReflectionFunction;
use ReflectionMethod;
2023-04-15 23:32:00 +08:00
use ReflectionParameter;
2022-01-25 15:35:48 +08:00
class Container implements ContainerInterface
{
2023-04-15 23:32:00 +08:00
2022-01-25 15:35:48 +08:00
/**
* @var array
*
* instance class by className
*/
private array $_singletons = [];
2023-04-15 23:32:00 +08:00
2022-01-25 15:35:48 +08:00
/**
* @var array
*
* implements \ReflectClass
*/
private array $_reflection = [];
2023-04-15 23:32:00 +08:00
2022-01-25 15:35:48 +08:00
/**
2023-04-15 23:32:00 +08:00
* @var array
2022-01-25 15:35:48 +08:00
*/
2023-04-15 23:32:00 +08:00
private array $_parameters = [];
2023-04-07 00:04:59 +08:00
/**
2023-04-15 23:32:00 +08:00
* @var array
2023-04-07 00:04:59 +08:00
*/
2023-04-15 23:32:00 +08:00
private array $_interfaces = [];
private static self|null $container = null;
private function __construct()
2023-04-07 00:04:59 +08:00
{
}
2023-04-15 23:32:00 +08:00
2022-09-08 11:31:12 +08:00
/**
* @return static
*/
2023-04-15 23:32:00 +08:00
public static function instance(): static
2022-09-08 11:31:12 +08:00
{
2023-04-15 23:32:00 +08:00
if (static::$container === null) {
static::$container = new Container();
2022-09-08 11:31:12 +08:00
}
return static::$container;
}
2023-04-15 23:32:00 +08:00
2022-01-25 15:35:48 +08:00
/**
2023-04-15 23:32:00 +08:00
* @param string $id
2022-01-25 15:35:48 +08:00
* @return mixed
2023-04-15 23:32:00 +08:00
* @throws ReflectionException
2022-01-25 15:35:48 +08:00
*/
2023-04-15 23:32:00 +08:00
public function get(string $id): mixed
2022-01-25 15:35:48 +08:00
{
2023-04-15 23:32:00 +08:00
if ($id === ContainerInterface::class) {
2022-01-25 15:35:48 +08:00
return $this;
}
2023-04-15 23:32:00 +08:00
if (!isset($this->_singletons[$id])) {
if (isset($this->_interfaces[$id])) {
$id = $this->_interfaces[$id];
2022-02-27 17:22:09 +08:00
}
2023-04-15 23:32:00 +08:00
$this->_singletons[$id] = $this->make($id);
2022-01-25 15:35:48 +08:00
}
2023-04-15 23:32:00 +08:00
return $this->_singletons[$id];
2022-01-25 15:35:48 +08:00
}
2023-04-15 23:32:00 +08:00
2023-04-16 00:59:31 +08:00
/**
* @param string $id
* @return void
* @throws ReflectionException
*/
public function parse(string $id): void
{
if (isset($this->_singletons[$id])) {
return;
}
$this->make($id);
}
2022-01-25 15:35:48 +08:00
/**
* @param string $interface
* @param string $class
2023-04-15 23:32:00 +08:00
* @return void
2022-01-25 15:35:48 +08:00
*/
2023-04-15 23:32:00 +08:00
public function set(string $interface, string $class): void
2022-01-25 15:35:48 +08:00
{
$this->_interfaces[$interface] = $class;
}
2023-04-15 23:32:00 +08:00
2023-04-16 00:15:10 +08:00
/**
* @param string $interface
* @param object $object
* @return void
*/
public function bind(string $interface, object $object): void
{
$this->_singletons[$interface] = $object;
}
2022-01-25 15:35:48 +08:00
/**
2023-04-15 23:32:00 +08:00
* @param string $className
* @return ReflectionClass
* @throws ReflectionException
2022-01-25 15:35:48 +08:00
*/
2023-04-15 23:32:00 +08:00
public function getReflectionClass(string $className): ReflectionClass
2022-01-25 15:35:48 +08:00
{
2023-04-15 23:32:00 +08:00
if (isset($this->_reflection[$className])) {
return $this->_reflection[$className];
2022-01-25 15:35:48 +08:00
}
2023-04-15 23:32:00 +08:00
$class = new ReflectionClass($className);
return $this->_reflection[$className] = $class;
2022-01-25 15:35:48 +08:00
}
2023-04-15 23:32:00 +08:00
2022-01-25 15:35:48 +08:00
/**
2023-04-15 23:32:00 +08:00
* @param string $className
* @param array $construct
2022-01-25 15:35:48 +08:00
* @param array $config
* @return object
* @throws ReflectionException
*/
2023-04-15 23:32:00 +08:00
public function make(string $className, array $construct = [], array $config = []): object
2022-01-25 15:35:48 +08:00
{
2023-04-15 23:32:00 +08:00
$reflect = $this->getReflectionClass($className);
2023-04-16 13:36:35 +08:00
$constructorHandler = $reflect->getConstructor();
if (count($construct) < 1 && $constructorHandler !== null) {
$construct = $this->getMethodParams($constructorHandler);
2022-01-25 15:35:48 +08:00
}
2023-04-15 23:32:00 +08:00
$object = self::configure($reflect->newInstanceArgs($construct), $config);
$this->resolveProperties($reflect, $object);
2023-04-16 13:47:32 +08:00
if (method_exists($object, 'init') && $className !== 'Symfony\Component\Console\Application') {
2023-04-16 02:18:22 +08:00
call_user_func([$object, 'init']);
}
2023-04-15 23:32:00 +08:00
return $object;
2022-01-25 15:35:48 +08:00
}
2023-04-15 23:32:00 +08:00
2022-01-25 15:35:48 +08:00
/**
2023-04-15 23:32:00 +08:00
* @param ReflectionClass $getReflectionClass
* @param object $class
* @return void
2022-01-25 15:35:48 +08:00
*/
2023-04-15 23:32:00 +08:00
public function resolveProperties(ReflectionClass $getReflectionClass, object $class): void
2022-01-25 15:35:48 +08:00
{
2023-04-15 23:32:00 +08:00
$properties = $getReflectionClass->getProperties();
2022-02-23 16:32:07 +08:00
foreach ($properties as $property) {
2023-04-15 23:32:00 +08:00
$propertyAttributes = $property->getAttributes();
foreach ($propertyAttributes as $attribute) {
$attribute->newInstance()->dispatch($class, $property->getName());
2022-02-23 16:32:07 +08:00
}
2022-01-25 15:35:48 +08:00
}
}
2023-04-15 23:32:00 +08:00
2022-01-25 15:35:48 +08:00
/**
2023-04-15 23:32:00 +08:00
* @param string $className
* @param string $method
* @return ReflectionMethod
2022-06-24 15:07:46 +08:00
* @throws ReflectionException
2022-01-25 15:35:48 +08:00
*/
2023-04-15 23:32:00 +08:00
public function getMethod(string $className, string $method): ReflectionMethod
2022-01-25 15:35:48 +08:00
{
2023-04-15 23:32:00 +08:00
$reflection = $this->getReflectionClass($className);
return $reflection->getMethod($method);
2022-01-25 15:35:48 +08:00
}
2023-04-15 23:32:00 +08:00
2022-01-25 15:35:48 +08:00
/**
2023-04-15 23:32:00 +08:00
* @param string $className
2022-01-25 15:35:48 +08:00
* @return ReflectionMethod[]
2022-06-16 17:38:22 +08:00
* @throws ReflectionException
2022-01-25 15:35:48 +08:00
*/
2023-04-15 23:32:00 +08:00
public function getMethods(string $className): array
2022-01-25 15:35:48 +08:00
{
2023-04-15 23:32:00 +08:00
$reflection = $this->getReflectionClass($className);
return $reflection->getMethods();
2022-01-25 15:35:48 +08:00
}
2023-04-15 23:32:00 +08:00
2022-01-25 15:35:48 +08:00
/**
2023-04-15 23:32:00 +08:00
* @param ReflectionMethod $parameters
* @return array
2022-01-25 15:35:48 +08:00
* @throws ReflectionException
*/
2023-04-15 23:32:00 +08:00
public function getMethodParams(ReflectionMethod $parameters): array
2022-01-25 15:35:48 +08:00
{
2023-04-15 23:32:00 +08:00
$className = $parameters->getDeclaringClass()->getName();
$methodName = $parameters->getName();
if (!isset($this->_parameters[$className])) {
return $this->_parameters[$className][$methodName] = $this->resolveMethodParams($parameters);
2022-01-25 15:35:48 +08:00
}
2023-04-15 23:32:00 +08:00
if (!isset($this->_parameters[$className][$methodName])) {
$this->_parameters[$className][$methodName] = $this->resolveMethodParams($parameters);
2023-03-30 18:35:19 +08:00
}
2023-04-15 23:32:00 +08:00
return $this->_parameters[$className][$methodName];
2022-01-25 15:35:48 +08:00
}
2023-04-15 23:32:00 +08:00
2022-01-25 15:35:48 +08:00
/**
2023-04-15 23:32:00 +08:00
* @param \Closure $parameters
* @return array
* @throws ReflectionException
2022-01-25 15:35:48 +08:00
*/
2023-04-15 23:32:00 +08:00
public function getFunctionParams(\Closure $parameters): array
2022-01-25 15:35:48 +08:00
{
2023-04-15 23:32:00 +08:00
return $this->resolveMethodParams(new ReflectionFunction($parameters));
2022-01-25 15:35:48 +08:00
}
2023-04-15 23:32:00 +08:00
2022-01-25 15:35:48 +08:00
/**
2023-04-15 23:32:00 +08:00
* @param ReflectionMethod|ReflectionFunction $parameters
2022-01-25 15:35:48 +08:00
* @return array
2023-04-15 23:32:00 +08:00
* @throws ReflectionException
2022-01-25 15:35:48 +08:00
*/
2023-04-15 23:32:00 +08:00
private function resolveMethodParams(ReflectionMethod|ReflectionFunction $parameters): array
2022-01-25 15:35:48 +08:00
{
$params = [];
2023-04-15 23:32:00 +08:00
if ($parameters->getNumberOfParameters() < 1) {
return $params;
}
$parametersArray = $parameters->getParameters();
2023-04-16 12:49:55 +08:00
$className = $parameters->getDeclaringClass()->getName();
2023-04-15 23:32:00 +08:00
foreach ($parametersArray as $parameter) {
$parameterAttributes = $parameter->getAttributes();
if (count($parameterAttributes) < 1) {
if ($parameter->isDefaultValueAvailable()) {
$value = $parameter->getDefaultValue();
} else if ($parameter->getType() === null) {
$value = $parameter->getType();
} else {
$value = $parameter->getType()->getName();
if (class_exists($value) || interface_exists($value)) {
$value = $this->get($value);
} else {
$value = $this->getTypeValue($parameter);
}
2022-01-25 15:35:48 +08:00
}
2023-04-15 23:32:00 +08:00
$params[$parameter->getName()] = $value;
} else {
$attribute = $parameterAttributes[0]->newInstance();
2023-04-16 12:49:55 +08:00
$params[$parameter->getName()] = $attribute->dispatch($className, $parameters->getName());
2022-01-25 15:35:48 +08:00
}
}
return $params;
}
2023-04-15 23:32:00 +08:00
2022-01-25 15:35:48 +08:00
/**
2023-04-15 23:32:00 +08:00
* @param ReflectionParameter $parameter
* @return string|int|bool|null
2022-01-25 15:35:48 +08:00
*/
2023-04-15 23:32:00 +08:00
private function getTypeValue(ReflectionParameter $parameter): string|int|bool|null
2022-01-25 15:35:48 +08:00
{
2023-04-15 23:32:00 +08:00
return match ($parameter->getType()) {
'string' => '',
'int', 'float' => 0,
'', null, 'object', 'mixed' => NULL,
'bool' => false,
'default' => null
};
2022-01-25 15:35:48 +08:00
}
2023-04-15 23:32:00 +08:00
2022-01-25 15:35:48 +08:00
/**
2023-04-15 23:32:00 +08:00
* @param object $object
* @param array $config
* @return object
2022-01-25 15:35:48 +08:00
*/
2023-04-15 23:32:00 +08:00
public static function configure(object $object, array $config): object
2022-01-25 15:35:48 +08:00
{
2023-04-15 23:32:00 +08:00
foreach ($config as $key => $value) {
if (!property_exists($object, $key)) {
continue;
}
$object->{$key} = $value;
2022-01-25 15:35:48 +08:00
}
2023-04-15 23:32:00 +08:00
return $object;
2022-01-25 15:35:48 +08:00
}
2023-04-15 23:32:00 +08:00
2022-01-25 15:35:48 +08:00
/**
* @param string $id
* @return bool
*/
public function has(string $id): bool
{
2023-04-15 23:32:00 +08:00
// TODO: Implement has() method.
return isset($this->_singletons[$id]) && isset($this->_reflection[$id]);
2022-01-25 15:35:48 +08:00
}
2023-04-15 23:32:00 +08:00
2022-01-25 15:35:48 +08:00
}