Compare commits
127 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f9e23c59ef | |||
| f89e8106f5 | |||
| 2f02c5af12 | |||
| 9e954135f6 | |||
| 7de790d65f | |||
| 855da03137 | |||
| 0081a30f22 | |||
| 3f2d3b0f04 | |||
| 5fa5646024 | |||
| 045c9293d5 | |||
| 6ae7f5a721 | |||
| 9775d16db5 | |||
| 03bffb5e5b | |||
| a21b949512 | |||
| 3f614ae8cd | |||
| cddf84c76a | |||
| 67a83e5712 | |||
| bedeaa63e2 | |||
| 052709d27d | |||
| ae8ba9ca4e | |||
| c6e9133566 | |||
| 4a168cb4a0 | |||
| de670304b5 | |||
| 048f49b27f | |||
| 950d23131e | |||
| 7d99a73c83 | |||
| e925a78f02 | |||
| dfada33039 | |||
| eeb06cf623 | |||
| 04b64bb4b8 | |||
| 00c089363f | |||
| 1d3c255be8 | |||
| ef3555eca1 | |||
| fe8d41ec41 | |||
| 5d8bc6d2cf | |||
| 500ebbf7f1 | |||
| 7b84c59fe9 | |||
| 0b6c62c41c | |||
| f552dc994c | |||
| c01514e516 | |||
| bed67a08bc | |||
| c54057e79c | |||
| 1b9c817ceb | |||
| d3cc7e7afe | |||
| ae11af9a7b | |||
| e4e0cc1d77 | |||
| 3ce9ee662a | |||
| cab51a97a9 | |||
| 13afca9c8f | |||
| dc49f51386 | |||
| bea41f0579 | |||
| 23206d2253 | |||
| 5ac43532af | |||
| 0a171da047 | |||
| 3611b87817 | |||
| b55d513f5b | |||
| d7ab423a0a | |||
| e1f76a476e | |||
| a6283ba90f | |||
| b15a4d233b | |||
| a5a958c43b | |||
| ef6672426a | |||
| 3244aed2e0 | |||
| 1b3101f07d | |||
| 2d0ee50758 | |||
| 75bae59d62 | |||
| f7768bbe40 | |||
| 6b2a71c6af | |||
| 764a7f4eb7 | |||
| 7b5b21b305 | |||
| 5e474fd9f4 | |||
| e3837281fa | |||
| 0b1016089e | |||
| ea844c3317 | |||
| c58b3080ad | |||
| dfc87000c0 | |||
| e5f048b778 | |||
| 478fe7a859 | |||
| 45e0ec0c17 | |||
| edfe966e83 | |||
| 9c67fb556f | |||
| 552785c16b | |||
| 9471104c79 | |||
| f8a4270b84 | |||
| 4b4bd185f5 | |||
| 8cde1f32ac | |||
| 728a2dd560 | |||
| 8890d03d2c | |||
| 2877f3faa5 | |||
| e9f3499f2f | |||
| 93f10ade37 | |||
| dc08bcd81f | |||
| ca7ec312b9 | |||
| efd8ad2f71 | |||
| b8d7e7052f | |||
| 43ce6b3486 | |||
| eebd01bcc5 | |||
| 06e2b691bb | |||
| 9a8d2b8bea | |||
| 293092f8d6 | |||
| 54230ffe75 | |||
| be23a272ba | |||
| f153fde08d | |||
| 73754f3bfb | |||
| e1687ed535 | |||
| f02b540f62 | |||
| d8b5990ee8 | |||
| 8a4dcd8475 | |||
| 7b67bc1dcf | |||
| 2dac0fa9af | |||
| c96db92b5b | |||
| c975458a17 | |||
| b9b1936611 | |||
| ce6e38a27e | |||
| 4af17359a7 | |||
| e7e951ab39 | |||
| 7f40dd8711 | |||
| d20d3f1b77 | |||
| 2ebf134a83 | |||
| d3d884b050 | |||
| b278f17175 | |||
| 1190a0d26c | |||
| 939f2304ee | |||
| b8993ecc56 | |||
| 0bf824b66e | |||
| 287abbfacf | |||
| ef274b00fc |
+357
-380
@@ -9,446 +9,423 @@ declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Di;
|
||||
|
||||
|
||||
use Closure;
|
||||
use Exception;
|
||||
use Kiri;
|
||||
use Kiri\Abstracts\Logger;
|
||||
use Kiri\Annotation\Inject;
|
||||
use Kiri\Di\Interface\InjectTargetInterface;
|
||||
use Kiri\Router\Interface\ValidatorInterface;
|
||||
use Kiri\Server\Task\OnTaskFinish;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ReflectionAttribute;
|
||||
use ReflectionClass;
|
||||
use ReflectionException;
|
||||
use ReflectionFunction;
|
||||
use ReflectionMethod;
|
||||
use ReflectionProperty;
|
||||
use ReflectionParameter;
|
||||
|
||||
|
||||
/**
|
||||
* Class Container
|
||||
* @package Kiri\Di
|
||||
*/
|
||||
class Container implements ContainerInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*
|
||||
* instance class by className
|
||||
*/
|
||||
private array $_singletons = [];
|
||||
|
||||
/**
|
||||
* @var ReflectionMethod[]
|
||||
*
|
||||
* class new instance construct parameter
|
||||
*/
|
||||
private array $_constructs = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*
|
||||
* implements \ReflectClass
|
||||
*/
|
||||
private array $_reflection = [];
|
||||
/**
|
||||
* @var array
|
||||
*
|
||||
* instance class by className
|
||||
*/
|
||||
private array $_singletons = [];
|
||||
|
||||
|
||||
/** @var array */
|
||||
private array $_parameters = [];
|
||||
/**
|
||||
* @var array
|
||||
*
|
||||
* implements \ReflectClass
|
||||
*/
|
||||
private array $_reflection = [];
|
||||
|
||||
|
||||
/** @var array|string[] */
|
||||
private array $_interfaces = [
|
||||
LoggerInterface::class => Logger::class
|
||||
];
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private array $_parameters = [];
|
||||
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @return mixed
|
||||
* @throws
|
||||
*/
|
||||
public function get(string $id): mixed
|
||||
{
|
||||
if ($id == ContainerInterface::class) {
|
||||
return $this;
|
||||
}
|
||||
return $this->make($id, [], []);
|
||||
}
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private array $_interfaces = [];
|
||||
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @param array $constrict
|
||||
* @param array $config
|
||||
* @return mixed
|
||||
* @throws
|
||||
*/
|
||||
public function make($class, array $constrict = [], array $config = []): mixed
|
||||
{
|
||||
if ($class == ContainerInterface::class) {
|
||||
return $this;
|
||||
}
|
||||
if ($this->isInterface($class)) {
|
||||
$class = $this->_interfaces[$class];
|
||||
}
|
||||
if (!isset($this->_singletons[$class])) {
|
||||
$this->_singletons[$class] = $this->resolve($class, $constrict, $config);
|
||||
}
|
||||
return $this->_singletons[$class];
|
||||
}
|
||||
/**
|
||||
* @var Container|null
|
||||
*/
|
||||
private static ?Container $container = null;
|
||||
|
||||
|
||||
/**
|
||||
* @param string $interface
|
||||
* @param string $class
|
||||
*/
|
||||
public function mapping(string $interface, string $class)
|
||||
{
|
||||
$this->_interfaces[$interface] = $class;
|
||||
}
|
||||
/**
|
||||
* Construct \ContainerInterface
|
||||
*/
|
||||
private function __construct()
|
||||
{
|
||||
$this->_singletons[ContainerInterface::class] = $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @return bool
|
||||
*/
|
||||
public function isInterface($class): bool
|
||||
{
|
||||
$reflect = $this->getReflect($class);
|
||||
if ($reflect->isInterface()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public static function instance(): static
|
||||
{
|
||||
if (static::$container === null) {
|
||||
static::$container = new Container();
|
||||
}
|
||||
return static::$container;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $interface
|
||||
* @param $object
|
||||
*/
|
||||
public function setBindings(string $interface, $object)
|
||||
{
|
||||
if (is_string($object)) {
|
||||
$this->_interfaces[$interface] = $object;
|
||||
} else {
|
||||
$className = get_class($object);
|
||||
$this->_interfaces[$interface] = $className;
|
||||
$this->_singletons[$className] = $object;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param string $id
|
||||
* @return mixed
|
||||
* @throws
|
||||
*/
|
||||
public function get(string $id): object
|
||||
{
|
||||
if (isset($this->_singletons[$id]))
|
||||
return $this->_singletons[$id];
|
||||
if (isset($this->_interfaces[$id])) {
|
||||
return $this->_singletons[$id] = $this->make($this->_interfaces[$id]);
|
||||
} else {
|
||||
return $this->_singletons[$id] = $this->make($id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @param array $constrict
|
||||
* @param array $config
|
||||
* @return object
|
||||
* @throws
|
||||
*/
|
||||
public function create($class, array $constrict = [], array $config = []): object
|
||||
{
|
||||
return $this->resolve($class, $constrict, $config);
|
||||
}
|
||||
/**
|
||||
* @param string $id
|
||||
* @return object
|
||||
* @throws
|
||||
*/
|
||||
public function parse(string $id): object
|
||||
{
|
||||
if (!isset($this->_singletons[$id])) {
|
||||
return $this->make($id);
|
||||
}
|
||||
return $this->_singletons[$id];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @param $constrict
|
||||
* @param $config
|
||||
*
|
||||
* @return object
|
||||
* @throws Exception
|
||||
*/
|
||||
private function resolve($class, $constrict, $config): object
|
||||
{
|
||||
$reflect = $this->resolveDependencies($class);
|
||||
if (!$reflect->isInstantiable()) {
|
||||
throw new ReflectionException('Class ' . $class . ' cannot be instantiated');
|
||||
}
|
||||
|
||||
$object = $this->newInstance($reflect, $constrict);
|
||||
|
||||
$this->propertyInject($reflect, $object);
|
||||
|
||||
return $this->onAfterInit($object, $config);
|
||||
}
|
||||
/**
|
||||
* @param string $interface
|
||||
* @param string $class
|
||||
* @return void
|
||||
*/
|
||||
public function set(string $interface, string $class): void
|
||||
{
|
||||
$this->_interfaces[$interface] = $class;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionClass $reflect
|
||||
* @param $dependencies
|
||||
* @return object
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
private function newInstance(ReflectionClass $reflect, $dependencies): object
|
||||
{
|
||||
if (!isset($this->_constructs[$reflect->getName()])) {
|
||||
return $reflect->newInstance();
|
||||
}
|
||||
$construct = $this->_constructs[$reflect->getName()];
|
||||
if ($construct->getNumberOfParameters() < 1) {
|
||||
return $reflect->newInstance();
|
||||
}
|
||||
$parameters = $this->mergeParam($this->resolveMethodParameters($construct), $dependencies);
|
||||
return $reflect->newInstanceArgs($parameters);
|
||||
}
|
||||
/**
|
||||
* @param string $interface
|
||||
* @param object $object
|
||||
* @return object
|
||||
*/
|
||||
public function bind(string $interface, object $object): object
|
||||
{
|
||||
$this->_singletons[$interface] = $object;
|
||||
return $object;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionClass $reflect
|
||||
* @param $object
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function propertyInject(ReflectionClass $reflect, $object): mixed
|
||||
{
|
||||
foreach (NoteManager::getPropertyAnnotation($reflect) as $property => $inject) {
|
||||
/** @var Inject $inject */
|
||||
$inject->execute($object, $property);
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
/**
|
||||
* @param string $className
|
||||
* @return ReflectionClass
|
||||
* @throws
|
||||
*/
|
||||
public function getReflectionClass(string $className): ReflectionClass
|
||||
{
|
||||
if (!isset($this->_reflection[$className])) {
|
||||
$this->_reflection[$className] = new ReflectionClass($className);
|
||||
}
|
||||
return $this->_reflection[$className];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $className
|
||||
* @param $method
|
||||
* @return array
|
||||
*/
|
||||
public function getMethodAttribute($className, $method = null): array
|
||||
{
|
||||
$methods = NoteManager::getMethodAnnotation($this->getReflect($className));
|
||||
if (!empty($method)) {
|
||||
return $methods[$method] ?? [];
|
||||
}
|
||||
return $methods;
|
||||
}
|
||||
/**
|
||||
* @param string $className
|
||||
* @param array $construct
|
||||
* @param array $config
|
||||
* @return object|null
|
||||
* @throws
|
||||
*/
|
||||
public function make(string $className, array $construct = [], array $config = []): ?object
|
||||
{
|
||||
$reflect = $this->getReflectionClass($className);
|
||||
if (!$reflect->isInstantiable()) {
|
||||
throw new ReflectionException('Class ' . $className . ' cannot be instantiated');
|
||||
}
|
||||
|
||||
if (empty($construct) && ($handler = $reflect->getConstructor()) !== null) {
|
||||
$construct = $this->getMethodParams($handler);
|
||||
}
|
||||
|
||||
$newInstance = $reflect->newInstanceArgs($construct);
|
||||
|
||||
return $this->runInit($reflect, static::configure($newInstance, $config));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @param string|null $property
|
||||
* @return ReflectionProperty|ReflectionProperty[]|null
|
||||
*/
|
||||
public function getClassReflectionProperty(string $class, string $property = null): ReflectionProperty|null|array
|
||||
{
|
||||
$lists = NoteManager::getProperty($this->getReflect($class));
|
||||
if (empty($lists)) {
|
||||
return null;
|
||||
}
|
||||
if (!empty($property)) {
|
||||
return $lists[$property] ?? null;
|
||||
}
|
||||
return $lists;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ReflectionClass $reflect
|
||||
* @param array $construct
|
||||
* @param array $config
|
||||
* @return object|null
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function makeReflection(ReflectionClass $reflect, array $construct = [], array $config = []): ?object
|
||||
{
|
||||
if (isset($this->_singletons[$reflect->getName()])) {
|
||||
return $this->_singletons[$reflect->getName()];
|
||||
}
|
||||
|
||||
if (!$reflect->isInstantiable()) {
|
||||
throw new ReflectionException('Class ' . $reflect->getName() . ' cannot be instantiated');
|
||||
}
|
||||
|
||||
if (empty($construct) && ($handler = $reflect->getConstructor()) !== null) {
|
||||
$construct = $this->getMethodParams($handler);
|
||||
}
|
||||
$newInstance = $reflect->newInstanceArgs($construct);
|
||||
|
||||
return $this->runInit($reflect, static::configure($newInstance, $config));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $object
|
||||
* @param $config
|
||||
* @return mixed
|
||||
*/
|
||||
private function onAfterInit($object, $config): mixed
|
||||
{
|
||||
Kiri::configure($object, $config);
|
||||
if (method_exists($object, 'init') && is_callable([$object, 'init'])) {
|
||||
call_user_func([$object, 'init']);
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
/**
|
||||
* @param ReflectionClass $reflect
|
||||
* @param object $object
|
||||
* @return void
|
||||
*/
|
||||
protected function injectClassTarget(ReflectionClass $reflect, object $object): void
|
||||
{
|
||||
$this->resolveProperties($reflect, $object);
|
||||
$attributes = $reflect->getAttributes();
|
||||
foreach ($attributes as $attribute) {
|
||||
if (class_exists($attribute->getName())) {
|
||||
$instance = $attribute->newInstance();
|
||||
if ($instance instanceof InjectTargetInterface) {
|
||||
$instance->dispatch($object::class);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @return ReflectionClass
|
||||
*/
|
||||
private function resolveDependencies($class): ReflectionClass
|
||||
{
|
||||
if (isset($this->_reflection[$class])) {
|
||||
return $this->_reflection[$class];
|
||||
}
|
||||
$reflect = new ReflectionClass($class);
|
||||
if ($reflect->isAbstract() || $reflect->isTrait() || $reflect->isInterface()) {
|
||||
return $this->_reflection[$class] = $reflect;
|
||||
}
|
||||
$construct = NoteManager::resolveTarget($reflect);
|
||||
if (!empty($construct) && $construct->getNumberOfParameters() > 0) {
|
||||
$this->_constructs[$class] = $construct;
|
||||
}
|
||||
return $this->_reflection[$class] = $reflect;
|
||||
}
|
||||
/**
|
||||
* @param ReflectionClass $reflect
|
||||
* @param object $object
|
||||
* @return object
|
||||
*/
|
||||
protected function runInit(ReflectionClass $reflect, object $object): object
|
||||
{
|
||||
$this->injectClassTarget($reflect, $object);
|
||||
if ($reflect->getName() === 'Symfony\Component\Console\Application') {
|
||||
return $object;
|
||||
}
|
||||
if (method_exists($object, 'init')) {
|
||||
call_user_func([$object, 'init']);
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionClass|string $class
|
||||
* @return ReflectionMethod[]
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function getReflectMethods(ReflectionClass|string $class): array
|
||||
{
|
||||
if (is_string($class)) {
|
||||
$class = $this->getReflect($class);
|
||||
}
|
||||
return NoteManager::getMethods($class);
|
||||
}
|
||||
/**
|
||||
* @param ReflectionClass $reflectionClass
|
||||
* @param object $class
|
||||
* @return void
|
||||
*/
|
||||
public function resolveProperties(ReflectionClass $reflectionClass, object $class): void
|
||||
{
|
||||
$properties = $reflectionClass->getProperties();
|
||||
foreach ($properties as $property) {
|
||||
$propertyAttributes = $property->getAttributes();
|
||||
foreach ($propertyAttributes as $attribute) {
|
||||
if (!class_exists($attribute->getName()) || $this->isValidatorInterface($attribute)) {
|
||||
continue;
|
||||
}
|
||||
$instance = $attribute->newInstance();
|
||||
$instance->dispatch($class, $property->getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionClass|string $class
|
||||
* @param string $method
|
||||
* @return ReflectionMethod|null
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function getReflectMethod(ReflectionClass|string $class, string $method): ?ReflectionMethod
|
||||
{
|
||||
return $this->getReflectMethods($class)[$method] ?? null;
|
||||
}
|
||||
/**
|
||||
* @param ReflectionAttribute $attribute
|
||||
* @return bool
|
||||
*/
|
||||
protected function isValidatorInterface(ReflectionAttribute $attribute): bool
|
||||
{
|
||||
return in_array(ValidatorInterface::class, class_implements($attribute->getName()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $className
|
||||
* @param string $method
|
||||
* @return ReflectionMethod
|
||||
* @throws
|
||||
*/
|
||||
public function getMethod(string $className, string $method): ReflectionMethod
|
||||
{
|
||||
$reflection = $this->getReflectionClass($className);
|
||||
|
||||
return $reflection->getMethod($method);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $className
|
||||
* @param string $method
|
||||
* @return array|null
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function getMethodParameters(string $className, string $method): ?array
|
||||
{
|
||||
if (isset($this->_parameters[$className]) && isset($this->_parameters[$className][$method])) {
|
||||
return $this->_parameters[$className][$method];
|
||||
}
|
||||
$reflectMethod = $this->getReflectMethod($this->getReflect($className), $method);
|
||||
if (!($reflectMethod instanceof ReflectionMethod)) {
|
||||
throw new ReflectionException("Class does not have a function $className::$method");
|
||||
}
|
||||
$className = $reflectMethod->getDeclaringClass()->getName();
|
||||
if (isset($this->_parameters[$className]) && isset($this->_parameters[$className][$reflectMethod->getName()])) {
|
||||
return $this->_parameters[$className][$reflectMethod->getName()];
|
||||
}
|
||||
return $this->setParameters($className, $reflectMethod->getName(), $this->resolveMethodParameters($reflectMethod));
|
||||
}
|
||||
/**
|
||||
* @param string $className
|
||||
* @return ReflectionMethod[]
|
||||
* @throws
|
||||
*/
|
||||
public function getMethods(string $className): array
|
||||
{
|
||||
$reflection = $this->getReflectionClass($className);
|
||||
|
||||
return $reflection->getMethods();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @param $method
|
||||
* @param $parameters
|
||||
* @return mixed
|
||||
*/
|
||||
private function setParameters($class, $method, $parameters): mixed
|
||||
{
|
||||
if (!isset($this->_parameters[$class])) {
|
||||
$this->_parameters[$class] = [];
|
||||
}
|
||||
return $this->_parameters[$class][$method] = $parameters;
|
||||
}
|
||||
/**
|
||||
* @param ReflectionMethod $parameters
|
||||
* @return array
|
||||
* @throws
|
||||
*/
|
||||
public function getMethodParams(ReflectionMethod $parameters): array
|
||||
{
|
||||
$className = $parameters->getDeclaringClass()->getName();
|
||||
$methodName = $parameters->getName();
|
||||
if (!isset($this->_parameters[$className]))
|
||||
$this->_parameters[$className] = [];
|
||||
if (!isset($this->_parameters[$className][$methodName])) {
|
||||
return $this->_parameters[$className][$methodName] = $this->resolveMethodParams($parameters);
|
||||
} else {
|
||||
return $this->_parameters[$className][$methodName];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Closure $reflectionMethod
|
||||
* @return array
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function getFunctionParameters(Closure $reflectionMethod): array
|
||||
{
|
||||
return $this->resolveMethodParameters(new ReflectionFunction($reflectionMethod));
|
||||
}
|
||||
/**
|
||||
* @param Closure $parameters
|
||||
* @return array
|
||||
* @throws
|
||||
*/
|
||||
public function getFunctionParams(Closure $parameters): array
|
||||
{
|
||||
return $this->resolveMethodParams(new ReflectionFunction($parameters));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionMethod|ReflectionFunction $reflectionMethod
|
||||
* @return array
|
||||
*/
|
||||
private function resolveMethodParameters(ReflectionMethod|ReflectionFunction $reflectionMethod): array
|
||||
{
|
||||
if ($reflectionMethod->getNumberOfParameters() < 1) {
|
||||
return [];
|
||||
}
|
||||
$params = [];
|
||||
foreach ($reflectionMethod->getParameters() as $key => $parameter) {
|
||||
if ($parameter->isDefaultValueAvailable()) {
|
||||
$params[$key] = $parameter->getDefaultValue();
|
||||
} else if ($parameter->getType() === null) {
|
||||
$params[$key] = $parameter->getType();
|
||||
} else {
|
||||
$type = $parameter->getType()->getName();
|
||||
if (is_string($type) && class_exists($type) || isset($this->_interfaces[$type])) {
|
||||
$type = Kiri::getDi()->get($type);
|
||||
}
|
||||
$params[$key] = match ($parameter->getType()) {
|
||||
'string' => '',
|
||||
'int', 'float' => 0,
|
||||
'', null, 'object', 'mixed' => NULL,
|
||||
'bool' => false,
|
||||
default => $type
|
||||
};
|
||||
}
|
||||
}
|
||||
return $params;
|
||||
}
|
||||
/**
|
||||
* @param ReflectionMethod|ReflectionFunction $parameters
|
||||
* @return array
|
||||
* @throws
|
||||
*/
|
||||
public function resolveMethodParams(ReflectionMethod|ReflectionFunction $parameters): array
|
||||
{
|
||||
$params = [];
|
||||
if ($parameters->getNumberOfParameters() < 1) {
|
||||
return $params;
|
||||
}
|
||||
$parametersArray = $parameters->getParameters();
|
||||
$class = $parameters->getDeclaringClass()->getName();
|
||||
foreach ($parametersArray as $parameter) {
|
||||
$parameterAttributes = $parameter->getAttributes();
|
||||
$name = $parameter->getName();
|
||||
if (count($parameterAttributes) > 0) {
|
||||
$attribute = $parameterAttributes[0]->newInstance();
|
||||
$params[$name] = $attribute->dispatch($class, $parameters->getName());
|
||||
} else {
|
||||
$params[$name] = $this->contractParams($parameter);
|
||||
}
|
||||
}
|
||||
return $params;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @return ReflectionClass|null
|
||||
*/
|
||||
public function getReflect($class): ?ReflectionClass
|
||||
{
|
||||
if (!isset($this->_reflection[$class])) {
|
||||
return $this->resolveDependencies($class);
|
||||
}
|
||||
return $this->_reflection[$class];
|
||||
}
|
||||
/**
|
||||
* @param $parameter
|
||||
* @return bool|int|mixed|object|string|null
|
||||
* @throws
|
||||
*/
|
||||
protected function contractParams($parameter): mixed
|
||||
{
|
||||
if ($parameter->isDefaultValueAvailable()) {
|
||||
return $parameter->getDefaultValue();
|
||||
}
|
||||
if ($parameter->getType() === null) {
|
||||
return $parameter->getType();
|
||||
}
|
||||
$value = $parameter->getType()->getName();
|
||||
if (class_exists($value) || interface_exists($value)) {
|
||||
return $this->get($value);
|
||||
} else {
|
||||
return $this->getTypeValue($parameter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
*/
|
||||
public function unset($class)
|
||||
{
|
||||
if (is_array($class) && isset($class['class'])) {
|
||||
$class = $class['class'];
|
||||
} else if (is_object($class)) {
|
||||
$class = $class::class;
|
||||
}
|
||||
unset(
|
||||
$this->_reflection[$class], $this->_singletons[$class], $this->_constructs[$class]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function flush(): static
|
||||
{
|
||||
$this->_reflection = [];
|
||||
$this->_singletons = [];
|
||||
$this->_constructs = [];
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* @param ReflectionParameter $parameter
|
||||
* @return string|int|bool|null|array
|
||||
* @throws
|
||||
*/
|
||||
private function getTypeValue(ReflectionParameter $parameter): string|int|bool|null|array
|
||||
{
|
||||
$class = $parameter->getDeclaringClass()->getName();
|
||||
$name = $parameter->getName();
|
||||
return match ($parameter->getType()->getName()) {
|
||||
'string' => '',
|
||||
'int', 'float' => 0,
|
||||
'', 'mixed' => NULL,
|
||||
'bool' => false,
|
||||
'object' => throw new Exception('Param type ' . $class . '::' . $name . ' must has default value.'),
|
||||
'array' => [],
|
||||
default => null
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param object $object
|
||||
* @param array $config
|
||||
* @return object
|
||||
*/
|
||||
public static function configure(object $object, array $config): object
|
||||
{
|
||||
foreach ($config as $key => $value) {
|
||||
if (!property_exists($object, $key)) {
|
||||
continue;
|
||||
}
|
||||
$object->{$key} = $value;
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @return bool
|
||||
*/
|
||||
public function has(string $id): bool
|
||||
{
|
||||
// TODO: Implement has() method.
|
||||
return isset($this->_singletons[$id]) && isset($this->_reflection[$id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $old
|
||||
* @param $newParam
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function mergeParam($old, $newParam): array
|
||||
{
|
||||
if (empty($old)) {
|
||||
return $newParam;
|
||||
} else if (empty($newParam)) {
|
||||
return $old;
|
||||
}
|
||||
foreach ($newParam as $key => $val) {
|
||||
$old[$key] = $val;
|
||||
}
|
||||
return $old;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @return bool
|
||||
*/
|
||||
public function has(string $id): bool
|
||||
{
|
||||
return isset($this->_singletons[$id]) || isset($this->_interfaces[$id]);
|
||||
}
|
||||
}
|
||||
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Di;
|
||||
|
||||
use Kiri\Di\Context\AsyncContext;
|
||||
use Kiri\Di\Context\ContextInterface;
|
||||
use Kiri\Di\Context\CoroutineContext;
|
||||
use Swoole\Coroutine;
|
||||
|
||||
/**
|
||||
* Class Context
|
||||
* @package Yoc\http
|
||||
* @mixin ContextInterface
|
||||
*/
|
||||
class Context
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
* @return mixed
|
||||
*/
|
||||
public static function __callStatic(string $name, array $arguments): mixed
|
||||
{
|
||||
// TODO: Implement __callStatic() method.
|
||||
if (static::inCoroutine()) {
|
||||
return call_user_func([CoroutineContext::class, $name], ...$arguments);
|
||||
} else {
|
||||
return call_user_func([AsyncContext::class, $name], ...$arguments);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function inCoroutine(): bool
|
||||
{
|
||||
return Coroutine::getCid() > -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
namespace Kiri\Di\Context;
|
||||
|
||||
class AsyncContext implements ContextInterface
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static array $context = [];
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function inCoroutine(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param int|null $coroutineId
|
||||
* @return mixed
|
||||
*/
|
||||
public static function set(string $key, mixed $value, ?int $coroutineId = null): mixed
|
||||
{
|
||||
// TODO: Implement set() method.
|
||||
return static::$context[$key] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed|null $defaultValue
|
||||
* @param int|null $coroutineId
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get(string $key, mixed $defaultValue = null, ?int $coroutineId = null): mixed
|
||||
{
|
||||
// TODO: Implement get() method.
|
||||
return static::$context[$key] ?? $defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param int|null $coroutineId
|
||||
* @return mixed
|
||||
*/
|
||||
public static function exists(string $key, ?int $coroutineId = null): bool
|
||||
{
|
||||
// TODO: Implement exists() method.
|
||||
return isset(static::$context[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param int|null $coroutineId
|
||||
* @return void
|
||||
*/
|
||||
public static function remove(string $key, ?int $coroutineId = null): void
|
||||
{
|
||||
// TODO: Implement remove() method.
|
||||
static::$context[$key] = null;
|
||||
unset(static::$context[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param int $value
|
||||
* @param int|null $coroutineId
|
||||
* @return int
|
||||
*/
|
||||
public static function increment(string $id, int $value = 1, ?int $coroutineId = null): int
|
||||
{
|
||||
if (!isset(static::$context[$id])) {
|
||||
static::$context[$id] = 0;
|
||||
}
|
||||
return static::$context[$id] += $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param int $value
|
||||
* @param int|null $coroutineId
|
||||
* @return int
|
||||
*/
|
||||
public static function decrement(string $id, int $value = 1, ?int $coroutineId = null): int
|
||||
{
|
||||
if (!isset(static::$context[$id])) {
|
||||
static::$context[$id] = 0;
|
||||
}
|
||||
return static::$context[$id] -= $value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Di\Context;
|
||||
|
||||
interface ContextInterface
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function inCoroutine(): bool;
|
||||
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param int|null $coroutineId
|
||||
* @return mixed
|
||||
*/
|
||||
public static function set(string $key, mixed $value, ?int $coroutineId = null): mixed;
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed|null $defaultValue
|
||||
* @param int|null $coroutineId
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get(string $key, mixed $defaultValue = null, ?int $coroutineId = null): mixed;
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param int|null $coroutineId
|
||||
* @return mixed
|
||||
*/
|
||||
public static function exists(string $key, ?int $coroutineId = null): bool;
|
||||
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param int|null $coroutineId
|
||||
* @return void
|
||||
*/
|
||||
public static function remove(string $key, ?int $coroutineId = null): void;
|
||||
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param int $value
|
||||
* @param int|null $coroutineId
|
||||
* @return int
|
||||
*/
|
||||
public static function increment(string $id, int $value = 1, ?int $coroutineId = null): int;
|
||||
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param int $value
|
||||
* @param int|null $coroutineId
|
||||
* @return int
|
||||
*/
|
||||
public static function decrement(string $id, int $value = 1, ?int $coroutineId = null): int;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Di\Context;
|
||||
|
||||
use Swoole\Coroutine;
|
||||
|
||||
class CoroutineContext implements ContextInterface
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function inCoroutine(): bool
|
||||
{
|
||||
return Coroutine::getCid() > -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param int|null $coroutineId
|
||||
* @return mixed
|
||||
*/
|
||||
public static function set(string $key, mixed $value, ?int $coroutineId = null): mixed
|
||||
{
|
||||
// TODO: Implement set() method.
|
||||
if (is_null($coroutineId)) {
|
||||
$coroutineId = Coroutine::getCid();
|
||||
}
|
||||
return Coroutine::getContext($coroutineId)[$key] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed|null $defaultValue
|
||||
* @param int|null $coroutineId
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get(string $key, mixed $defaultValue = null, ?int $coroutineId = null): mixed
|
||||
{
|
||||
// TODO: Implement get() method.
|
||||
if (is_null($coroutineId)) {
|
||||
$coroutineId = Coroutine::getCid();
|
||||
}
|
||||
return Coroutine::getContext($coroutineId)[$key] ?? $defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param int|null $coroutineId
|
||||
* @return mixed
|
||||
*/
|
||||
public static function exists(string $key, ?int $coroutineId = null): bool
|
||||
{
|
||||
// TODO: Implement exists() method.
|
||||
if (is_null($coroutineId)) {
|
||||
$coroutineId = Coroutine::getCid();
|
||||
}
|
||||
return isset(Coroutine::getContext($coroutineId)[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param int|null $coroutineId
|
||||
* @return void
|
||||
*/
|
||||
public static function remove(string $key, ?int $coroutineId = null): void
|
||||
{
|
||||
// TODO: Implement remove() method.
|
||||
if (is_null($coroutineId)) {
|
||||
$coroutineId = Coroutine::getCid();
|
||||
}
|
||||
Coroutine::getContext($coroutineId)[$key] = null;
|
||||
unset(Coroutine::getContext($coroutineId)[$key]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param int $value
|
||||
* @param int|null $coroutineId
|
||||
* @return int
|
||||
*/
|
||||
public static function increment(string $id, int $value = 1, ?int $coroutineId = null): int
|
||||
{
|
||||
if (is_null($coroutineId)) {
|
||||
$coroutineId = Coroutine::getCid();
|
||||
}
|
||||
if (!isset(Coroutine::getContext($coroutineId)[$id])) {
|
||||
Coroutine::getContext($coroutineId)[$id] = 0;
|
||||
}
|
||||
return Coroutine::getContext($coroutineId)[$id] += $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param int $value
|
||||
* @param int|null $coroutineId
|
||||
* @return int
|
||||
*/
|
||||
public static function decrement(string $id, int $value = 1, ?int $coroutineId = null): int
|
||||
{
|
||||
if (is_null($coroutineId)) {
|
||||
$coroutineId = Coroutine::getCid();
|
||||
}
|
||||
if (!isset(Coroutine::getContext($coroutineId)[$id])) {
|
||||
Coroutine::getContext($coroutineId)[$id] = 0;
|
||||
}
|
||||
return Coroutine::getContext($coroutineId)[$id] -= $value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Di\Inject;
|
||||
|
||||
use Kiri\Di\Interface\InjectPropertyInterface;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||
class Config implements InjectPropertyInterface
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*/
|
||||
public function __construct(public string $key)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param object $class
|
||||
* @param string $property
|
||||
* @return void
|
||||
*/
|
||||
public function dispatch(object $class, string $property): void
|
||||
{
|
||||
// TODO: Implement dispatch() method.
|
||||
$class->{$property} = config($this->key);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Di\Inject;
|
||||
|
||||
|
||||
use Kiri\Di\Interface\InjectPropertyInterface;
|
||||
use Kiri\Di\Container as DContainer;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||
class Container implements InjectPropertyInterface
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param string $service
|
||||
* @param mixed|null $default
|
||||
* @throws
|
||||
*/
|
||||
public function __construct(readonly public string $service, public mixed $default = null)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param object $class
|
||||
* @param string $property
|
||||
* @return void
|
||||
* @throws
|
||||
*/
|
||||
public function dispatch(object $class, string $property): void
|
||||
{
|
||||
$class->{$property} = DContainer::instance()->get($this->service);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
namespace Kiri\Di\Inject;
|
||||
|
||||
|
||||
use Exception;
|
||||
use Kiri\Di\Container;
|
||||
use Kiri\Di\Interface\InjectParameterInterface;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PARAMETER)]
|
||||
class ContainerParams implements InjectParameterInterface
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __construct(readonly public mixed $value)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return mixed|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function dispatch(string $class, string $method): mixed
|
||||
{
|
||||
return Container::instance()->get($this->value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri\Di\Inject;
|
||||
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||
class Skip
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri\Di\Interface;
|
||||
|
||||
interface InjectMethodInterface
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @param string $method
|
||||
* @return void
|
||||
*/
|
||||
public function dispatch(string $class, string $method): void;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Di\Interface;
|
||||
|
||||
interface InjectParameterInterface
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @param string $method
|
||||
* @return mixed
|
||||
*/
|
||||
public function dispatch(string $class, string $method): mixed;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Di\Interface;
|
||||
|
||||
interface InjectPropertyInterface
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param object $class
|
||||
* @param string $property
|
||||
* @return void
|
||||
*/
|
||||
public function dispatch(object $class, string $property): void;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri\Di\Interface;
|
||||
|
||||
interface InjectTargetInterface
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @return void
|
||||
*/
|
||||
public function dispatch(string $class): void;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Di\Interface;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
|
||||
/**
|
||||
* Response Emitter Interface
|
||||
*/
|
||||
interface ResponseEmitterInterface
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param ResponseInterface $proxy
|
||||
* @param object $response
|
||||
* @param object $request
|
||||
* @return void
|
||||
*/
|
||||
public function response(ResponseInterface $proxy, object $response, object $request): void;
|
||||
|
||||
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri\Di;
|
||||
|
||||
use Kiri\Abstracts\Component;
|
||||
use Kiri;
|
||||
|
||||
|
||||
/**
|
||||
* 服务定位器
|
||||
*/
|
||||
class LocalService extends Component
|
||||
{
|
||||
|
||||
|
||||
private array $_components = [];
|
||||
|
||||
|
||||
private array $_definition = [];
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $define
|
||||
*/
|
||||
public function set($name, $define)
|
||||
{
|
||||
unset($this->_components[$name]);
|
||||
|
||||
$this->_definition[$name] = $define;
|
||||
if (is_object($define) || $define instanceof \Closure) {
|
||||
$this->_components[$name] = $define;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function get(string $name, $throwException = true)
|
||||
{
|
||||
if (isset($this->_components[$name])) {
|
||||
return $this->_components[$name];
|
||||
}
|
||||
if (isset($this->_definition[$name])) {
|
||||
$definition = $this->_definition[$name];
|
||||
if (is_object($definition) && !$definition instanceof \Closure) {
|
||||
return $this->_components[$name] = $definition;
|
||||
}
|
||||
return $this->_components[$name] = Kiri::createObject($definition);
|
||||
} else if ($throwException) {
|
||||
throw new \Exception("Unknown component ID: $name");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $components
|
||||
*/
|
||||
public function setComponents(array $components)
|
||||
{
|
||||
foreach ($components as $name => $component) {
|
||||
$this->set($name, $component);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @return bool
|
||||
*/
|
||||
public function has($id): bool
|
||||
{
|
||||
return isset($this->_components[$id]) || isset($this->_definition[$id]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
*/
|
||||
public function remove($id): void
|
||||
{
|
||||
unset($this->_components[$id], $this->_definition[$id]);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
-303
@@ -1,303 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri\Di;
|
||||
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use ReflectionAttribute;
|
||||
use ReflectionClass;
|
||||
use ReflectionProperty;
|
||||
|
||||
class NoteManager
|
||||
{
|
||||
|
||||
|
||||
private static array $_classTarget = [];
|
||||
private static array $_classMethodAnnotation = [];
|
||||
private static array $_classMethod = [];
|
||||
private static array $_classPropertyAnnotation = [];
|
||||
private static array $_classProperty = [];
|
||||
private static array $_mapping = [];
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public static function clear()
|
||||
{
|
||||
static::$_classTarget = [];
|
||||
static::$_classMethodAnnotation = [];
|
||||
static::$_classMethod = [];
|
||||
static::$_classPropertyAnnotation = [];
|
||||
static::$_classProperty = [];
|
||||
static::$_mapping = [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionClass $class
|
||||
*/
|
||||
public static function setTargetAnnotation(ReflectionClass $class)
|
||||
{
|
||||
$className = $class->getName();
|
||||
if (!isset(static::$_classTarget[$className])) {
|
||||
static::$_classTarget[$className] = [];
|
||||
}
|
||||
foreach ($class->getAttributes() as $attribute) {
|
||||
if (!class_exists($attribute->getName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$instance = $attribute->newInstance();
|
||||
|
||||
static::$_classTarget[$className][] = $instance;
|
||||
|
||||
self::setMappingClass($attribute, $className);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionAttribute $attribute
|
||||
* @param string $class
|
||||
*/
|
||||
public static function setMappingClass(ReflectionAttribute $attribute, string $class)
|
||||
{
|
||||
if (!isset(static::$_mapping[$attribute->getName()])) {
|
||||
static::$_mapping[$attribute->getName()] = [];
|
||||
}
|
||||
if (!isset(static::$_mapping[$attribute->getName()][$class])) {
|
||||
static::$_mapping[$attribute->getName()][$class] = [];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionAttribute $attribute
|
||||
* @param string $class
|
||||
* @param string $method
|
||||
* @param mixed $instance
|
||||
*/
|
||||
public static function setMappingMethod(ReflectionAttribute $attribute, string $class, string $method, mixed $instance)
|
||||
{
|
||||
self::setMappingClass($attribute, $class);
|
||||
|
||||
if (!isset(static::$_mapping[$attribute->getName()][$class]['method'])) {
|
||||
static::$_mapping[$attribute->getName()][$class]['method'] = [];
|
||||
}
|
||||
static::$_mapping[$attribute->getName()][$class]['method'][] = [$method => $instance];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionAttribute $attribute
|
||||
* @param string $class
|
||||
* @param string $property
|
||||
* @param $instance
|
||||
*/
|
||||
public static function setMappingProperty(ReflectionAttribute $attribute, string $class, string $property, $instance)
|
||||
{
|
||||
self::setMappingClass($attribute, $class);
|
||||
|
||||
$mapping = static::$_mapping[$attribute->getName()][$class];
|
||||
if (!isset($mapping['property'])) {
|
||||
$mapping['property'] = [];
|
||||
}
|
||||
$mapping['property'][] = [$property => $instance];
|
||||
static::$_mapping[$attribute->getName()][$class] = $mapping;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $class
|
||||
* @return array
|
||||
*/
|
||||
public static function getTargetAnnotation(mixed $class): array
|
||||
{
|
||||
if (!is_string($class)) {
|
||||
$class = $class::class;
|
||||
}
|
||||
return static::$_classTarget[$class] ?? [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionClass $class
|
||||
*/
|
||||
public static function setMethodAnnotation(ReflectionClass $class)
|
||||
{
|
||||
$className = $class->getName();
|
||||
static::$_classMethodAnnotation[$className] = static::$_classMethod[$className] = [];
|
||||
foreach ($class->getMethods() as $ReflectionMethod) {
|
||||
static::$_classMethod[$className][$ReflectionMethod->getName()] = $ReflectionMethod;
|
||||
static::$_classMethodAnnotation[$className][$ReflectionMethod->getName()] = [];
|
||||
foreach ($ReflectionMethod->getAttributes() as $attribute) {
|
||||
if (!class_exists($attribute->getName())) {
|
||||
continue;
|
||||
}
|
||||
$instance = $attribute->newInstance();
|
||||
|
||||
static::$_classMethodAnnotation[$className][$ReflectionMethod->getName()][] = $instance;
|
||||
|
||||
self::setMappingMethod($attribute, $className, $ReflectionMethod->getName(), $instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @param string $method
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasMethod(string $class, string $method): bool
|
||||
{
|
||||
return isset(static::$_classMethod[$class]) && isset(static::$_classMethod[$class][$method]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionClass $class
|
||||
* @return array
|
||||
*/
|
||||
#[Pure] public static function getMethodAnnotation(ReflectionClass $class): array
|
||||
{
|
||||
return static::$_classMethodAnnotation[$class->getName()] ?? [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param \ReflectionClass $reflect
|
||||
* @return \ReflectionMethod|null
|
||||
*/
|
||||
public static function resolveTarget(ReflectionClass $reflect): ?\ReflectionMethod
|
||||
{
|
||||
NoteManager::setPropertyAnnotation($reflect);
|
||||
NoteManager::setTargetAnnotation($reflect);
|
||||
NoteManager::setMethodAnnotation($reflect);
|
||||
|
||||
return $reflect->getConstructor();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionClass $class
|
||||
*/
|
||||
public static function setPropertyAnnotation(ReflectionClass $class)
|
||||
{
|
||||
$className = $class->getName();
|
||||
static::$_classProperty[$className] = static::$_classPropertyAnnotation[$className] = [];
|
||||
foreach ($class->getProperties(ReflectionProperty::IS_PRIVATE | ReflectionProperty::IS_PUBLIC |
|
||||
ReflectionProperty::IS_PROTECTED) as $ReflectionMethod) {
|
||||
static::$_classProperty[$className][$ReflectionMethod->getName()] = $ReflectionMethod;
|
||||
foreach ($ReflectionMethod->getAttributes() as $attribute) {
|
||||
if (!class_exists($attribute->getName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$instance = $attribute->newInstance();
|
||||
|
||||
static::$_classPropertyAnnotation[$className][$ReflectionMethod->getName()] = $instance;
|
||||
|
||||
self::setMappingProperty($attribute, $className, $ReflectionMethod->getName(), $instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $attribute
|
||||
* @param string|null $class
|
||||
* @return array[]
|
||||
*/
|
||||
public static function getAttributeTrees(string $attribute, string $class = null): array
|
||||
{
|
||||
$mapping = static::$_mapping[$attribute] ?? [];
|
||||
if (empty($mapping) || empty($class)) {
|
||||
return $mapping;
|
||||
}
|
||||
return $mapping[$class] ?? [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $attribute
|
||||
* @param string $class
|
||||
* @param string|null $method
|
||||
* @return array
|
||||
*/
|
||||
public static function getSpecify_annotation(string $attribute, string $class, string $method = null): mixed
|
||||
{
|
||||
$class = self::getAttributeTrees($attribute, $class);
|
||||
if (empty($class) || !isset($class['method'])) {
|
||||
return null;
|
||||
}
|
||||
if (empty($method)) {
|
||||
return $class['method'];
|
||||
}
|
||||
foreach ($class['method'] as $value) {
|
||||
$key = key($value);
|
||||
if ($method == $key) {
|
||||
return $value[$key];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $attribute
|
||||
* @param string $class
|
||||
* @param string $method
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getPropertyByAnnotation(string $attribute, string $class, string $method): mixed
|
||||
{
|
||||
$class = self::getAttributeTrees($attribute, $class);
|
||||
if (empty($class) || !isset($class['property'])) {
|
||||
return [];
|
||||
}
|
||||
foreach ($class['property'] as $value) {
|
||||
$key = key($value);
|
||||
if ($method == $key) {
|
||||
return $value[$key];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionClass|string $class
|
||||
* @return array
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public static function getMethods(ReflectionClass|string $class): array
|
||||
{
|
||||
if (is_string($class)) {
|
||||
$class = self::getReflect($class);
|
||||
}
|
||||
return static::$_classMethod[$class->getName()] ?? [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionClass $class
|
||||
* @return ReflectionProperty[]
|
||||
*/
|
||||
#[Pure] public static function getProperty(ReflectionClass $class): array
|
||||
{
|
||||
return static::$_classProperty[$class->getName()] ?? [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionClass $class
|
||||
* @return array
|
||||
*/
|
||||
#[Pure] public static function getPropertyAnnotation(ReflectionClass $class): array
|
||||
{
|
||||
return static::$_classPropertyAnnotation[$class->getName()] ?? [];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
namespace Kiri\Di;
|
||||
|
||||
use Kiri\Di\Inject\Container;
|
||||
use Kiri\Abstracts\Component;
|
||||
use Kiri\Di\Inject\Skip;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use ReflectionClass;
|
||||
use ReflectionMethod;
|
||||
|
||||
class Scanner extends Component
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
#[Container(ContainerInterface::class)]
|
||||
public ContainerInterface $container;
|
||||
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public array $files = [];
|
||||
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @return void
|
||||
* @throws
|
||||
*/
|
||||
public function load_directory(string $path): void
|
||||
{
|
||||
$dir = new \DirectoryIterator($path);
|
||||
$skip = \config('site.scanner.skip', []);
|
||||
foreach ($dir as $value) {
|
||||
if ($value->isDot() || str_starts_with($value->getFilename(), '.')) {
|
||||
continue;
|
||||
}
|
||||
if ($value->isDir()) {
|
||||
if (in_array($value->getRealPath() . '/', $skip)) {
|
||||
continue;
|
||||
}
|
||||
$this->load_directory($value->getRealPath());
|
||||
} else if ($value->getExtension() == 'php') {
|
||||
if (in_array($value->getRealPath(), $this->files)) {
|
||||
continue;
|
||||
}
|
||||
$this->files[] = $value->getRealPath();
|
||||
$this->load_file($value->getRealPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
* @return string
|
||||
*/
|
||||
private function rename(string $file): string
|
||||
{
|
||||
$filter = array_filter(explode('/', $file), function ($value) {
|
||||
if (empty($value)) {
|
||||
return false;
|
||||
}
|
||||
return ucfirst($value);
|
||||
});
|
||||
return ucfirst(implode('\\', $filter));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @return void
|
||||
* @throws
|
||||
*/
|
||||
private function load_file(string $path): void
|
||||
{
|
||||
try {
|
||||
opcache_invalidate($path);
|
||||
opcache_compile_file($path);
|
||||
|
||||
require_once "$path";
|
||||
if (!isset($_SERVER['PWD'])) {
|
||||
$_SERVER['PWD'] = APP_PATH;
|
||||
}
|
||||
$path = str_replace($_SERVER['PWD'], '', $path);
|
||||
$path = str_replace('.php', '', $path);
|
||||
$this->parseFile($path);
|
||||
} catch (\Throwable $throwable) {
|
||||
error($throwable);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $file
|
||||
* @return void
|
||||
* @throws
|
||||
*/
|
||||
protected function parseFile($file): void
|
||||
{
|
||||
$class = $this->rename($file);
|
||||
if (class_exists($class)) {
|
||||
$reflect = $this->container->getReflectionClass($class);
|
||||
if ($reflect->isInstantiable()) {
|
||||
if ($reflect->isTrait() || $reflect->isEnum() || $reflect->isInterface()) {
|
||||
return;
|
||||
}
|
||||
$attributes = $this->skipNames($reflect);
|
||||
if (in_array(Skip::class, $attributes) || in_array(\Attribute::class, $attributes)) {
|
||||
return;
|
||||
}
|
||||
foreach ($reflect->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
|
||||
if ($method->isStatic() || $method->getDeclaringClass()->getName() != $class) {
|
||||
continue;
|
||||
}
|
||||
$attributes = $method->getAttributes();
|
||||
foreach ($attributes as $attribute) {
|
||||
if (!class_exists($attribute->getName())) {
|
||||
continue;
|
||||
}
|
||||
$instance = $attribute->newInstance();
|
||||
if (!method_exists($instance, 'dispatch')) {
|
||||
continue;
|
||||
}
|
||||
$instance->dispatch($class, $method->getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionClass $reflect
|
||||
* @return array
|
||||
*/
|
||||
protected function skipNames(ReflectionClass $reflect): array
|
||||
{
|
||||
$attributes = $reflect->getAttributes();
|
||||
$names = [];
|
||||
foreach ($attributes as $attribute) {
|
||||
$names[] = $attribute->getName();
|
||||
}
|
||||
return $names;
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -9,7 +9,8 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": ">=8.0"
|
||||
"php": ">=8.4",
|
||||
"psr/container": "^2.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
||||
Reference in New Issue
Block a user