_singletons[$class])) { return $this->_singletons[$class]; } else if (!isset($this->_constructs[$class])) { return $this->resolve($class, $constrict, $config); } $definition = $this->_constructs[$class]; if (is_callable($definition, TRUE)) { return call_user_func($definition, $this, $constrict, $config); } else if (is_array($definition)) { $object = $this->resolveDefinition($definition, $class, $config, $constrict); } else if (is_object($definition)) { return $this->_singletons[$class] = $definition; } else { throw new NotFindClassException($class); } return $this->_singletons[$class] = $object; } /** * @param $definition * @param $class * @param $config * @param $constrict * @return mixed * @throws NotFindClassException * @throws ReflectionException */ private function resolveDefinition($definition, $class, $config, $constrict) { if (!isset($definition['class'])) { throw new NotFindClassException($class); } $_className = $definition['class']; unset($definition['class']); $config = array_merge($definition, $config); $definition = $this->mergeParam($class, $constrict); if ($_className === $class) { $object = $this->resolve($class, $definition, $config); } else { $object = $this->get($class, $definition, $config); } return $object; } /** * @param $class * @param $constrict * @param $config * * @return object * @throws NotFindClassException * @throws ReflectionException */ private function resolve($class, $constrict, $config): object { [$reflect, $dependencies] = $this->resolveDependencies($class, $constrict); foreach ($constrict as $index => $param) { $dependencies[$index] = $param; } if (!$reflect->isInstantiable()) { throw new NotFindClassException($reflect->getName()); } if (empty($config) || !is_array($config)) { return $reflect->newInstanceArgs($dependencies); } if (!empty($dependencies) && $reflect->implementsInterface('Snowflake\Abstracts\Configure')) { $dependencies[count($dependencies) - 1] = $config; return $reflect->newInstanceArgs($dependencies); } if (!empty($config)) $this->_param[$class] = $config; return $this->onAfterInit($reflect->newInstanceArgs($dependencies), $config); } /** * @param $object * @param $config * @return mixed */ private function onAfterInit($object, $config) { Snowflake::configure($object, $config); if (method_exists($object, 'afterInit')) { call_user_func([$object, 'afterInit']); } return $object; } /** * @param $class * @param array $constrict * @return array|null * @throws NotFindClassException * @throws ReflectionException */ private function resolveDependencies($class, $constrict = []): ?array { if (!isset($this->_reflection[$class])) { if (!class_exists($class)) { return null; } $reflection = new ReflectionClass($class); if (!$reflection->isInstantiable()) { return null; } $this->_reflection[$class] = $reflection; } else { $reflection = $this->_reflection[$class]; } if (!is_null($construct = $reflection->getConstructor())) { $constrict = $this->resolveMethodParam($construct); } return [$reflection, $constrict]; } /** * @param \ReflectionMethod|null $method * @return array * @throws NotFindClassException * @throws ReflectionException */ private function resolveMethodParam(?\ReflectionMethod $method): array { $array = []; foreach ($method->getParameters() as $key => $parameter) { if ($parameter->isDefaultValueAvailable()) { $array[] = $parameter->getDefaultValue(); } else { $type = $parameter->getType(); if (is_string($type) && class_exists($type)) { $type = Snowflake::createObject($type); } $array[] = match ($parameter->getType()) { 'string' => '', 'int', 'float' => 0, '', null, 'object', 'mixed' => NULL, 'bool' => false, default => $type }; } } return $array; } /** * @param $class * @return ReflectionClass|null * @throws NotFindClassException * @throws ReflectionException */ public function getReflect($class): ?ReflectionClass { $reflect = $this->_reflection[$class] ?? null; if (!is_null($reflect)) { return $reflect; } $reflect = $this->resolveDependencies($class); if (is_array($reflect)) { return $reflect[0]; } return null; } /** * @param $class */ public function unset($class) { if (is_array($class) && isset($class['class'])) { $class = $class['class']; } else if (is_object($class)) { $class = get_class($class); } unset( $this->_reflection[$class], $this->_singletons[$class], $this->_param[$class], $this->_constructs[$class] ); } /** * @return $this */ public function flush(): static { $this->_reflection = []; $this->_singletons = []; $this->_param = []; $this->_constructs = []; return $this; } /** * @param $class * @param $newParam * * @return mixed */ private function mergeParam($class, $newParam): array { if (empty($this->_param[$class])) { return $newParam; } else if (empty($newParam)) { return $this->_param[$class]; } $old = $this->_param[$class]; foreach ($newParam as $key => $val) { $old[$key] = $val; } return $old; } }