乐趣区

关于php:从binswoft开始阅读Swoft框架源码六二BeanProcessor之bean配置解析

通过上一节的注解解析后,swoft 将获取到的注解对象解析成了定义对象, 实现了对这些原始注解对象的梳理工作.

本大节将梳理获取到的这些定义对象的解析.

解析定义对象的入口办法:

private function parseDefinitions(): void
{
     // 实例化解析器, 将后面解析好的数据传递进去
     $annotationParser = new DefinitionObjParser(
         $this->definitions,
         $this->objectDefinitions,
         $this->classNames,
         $this->aliases
     );
     // 调用解析器的解析办法
     // Collect info
     $definitionData = $annotationParser->parseDefinitions();
     // 将返回的后果保留在容器上
     [$this->definitions, $this->objectDefinitions, $this->classNames, $this->aliases] = $definitionData;
}

解析器的入口办法:

public function parseDefinitions(): array
{// 遍历 bean 配置, 失去 bean 名称和配置(定义)
     foreach ($this->definitions as $beanName => $definition) {
         // 如果曾经通过上一节的注解解析, 生成了这个定义对象
         if (isset($this->objectDefinitions[$beanName])) {
             // 获取这个定义对象
             $objectDefinition = $this->objectDefinitions[$beanName];
             // 重置这个定义对象
             $this->resetObjectDefinition($beanName, $objectDefinition, $definition);
             // 持续下一个
             continue; 
         }
         // 否则, 依据 bean 配置创立定义对象
         $this->createObjectDefinition($beanName, $definition);
     }
     return [$this->definitions, $this->objectDefinitions, $this->classNames, $this->aliases];
}

重置定义对象:

private function resetObjectDefinition(string $beanName, ObjectDefinition $objDefinition, array $definition): void
{
     // 获取 bean 配置中定义的类名
     // Parse class name
     $className = $definition['class'] ?? '';
     // 获取定义对象的类名
     $objClassName = $objDefinition->getClassName();
     // 如果配置中定义了类名且与定义对象中的类名不同, 抛出异样
     if (!empty($className) && $className !== $objClassName) {throw new InvalidArgumentException('Class for annotations and definitions must be the same Or not to define class');
     }
     // 更新定义对象
     $objDefinition = $this->updateObjectDefinitionByDefinition($objDefinition, $definition);
     // 将更新后的定义对象设置回定义对象池
     $this->objectDefinitions[$beanName] = $objDefinition;
}

更新定义对象办法:

private function updateObjectDefinitionByDefinition(ObjectDefinition $objDfn, array $definition): ObjectDefinition
{
     // 将 bean 配置解析成结构参数注入对象、属性注入对象数组、选项数组
     [$constructInject, $propertyInjects, $option] = $this->parseDefinition($definition);
     // 设置结构注入
     // Set construct inject
     if (!empty($constructInject)) {$objDfn->setConstructorInjection($constructInject);
     }
     // 遍历属性注入数组并设置到定义对象中
     // Set property inject
     foreach ($propertyInjects as $propertyName => $propertyInject) {
        // 设置属性注入对象
        // 如果曾经有这个属性的设置, 则回被笼罩
        $objDfn->setPropertyInjection($propertyName, $propertyInject);
     }
     // 类型数组
     $scopes = [
         Bean::SINGLETON,
         Bean::PROTOTYPE,
         Bean::REQUEST,
     ];
     // 获取选项中的类型定义
     $scope = $option['scope'] ?? '';
     // 获取选项中的别名定义
     $alias = $option['alias'] ?? '';
     // 也就是说不能在这里定义 session 类型
     if (!empty($scope) && !in_array($scope, $scopes, true)) {throw new InvalidArgumentException('Scope for definition is not undefined');
     }
     // 设置类型
     // Update scope
     if (!empty($scope)) {$objDfn->setScope($scope);
     }
     // 更新别名
     // 感觉这里的代码是有问题的
     // 获取对象原始别名和删除别名映射的操作是不是应该放在
     // 设置操作的后面?
     // 否则这一步操作就等于没有删除后面定义的别名
     // 且设置了新的别名
     // Update alias
     if (!empty($alias)) {
         // 设置定义对象的别名
         $objDfn->setAlias($alias);
         // 获取定义对象别名
         $objAlias = $objDfn->getAlias();
         unset($this->aliases[$objAlias]);
         // 设置新的别名
         $this->aliases[$alias] = $objDfn->getName();}
     // 返回曾经更新的定义对象
     return $objDfn;
}

bean 配置解析:

private function parseDefinition(array $definition): array
{
     // Remove class key
     // 移除类名的定义
     unset($definition['class']);
     
     // Parse construct
     // 获取结构参数
     $constructArgs = $definition[0] ?? [];
     if (!is_array($constructArgs)) {throw new InvalidArgumentException('Construct args for definition must be array');
     }
     
     // Parse construct args
     $argInjects = [];
     // 遍历结构参数
     foreach ($constructArgs as $arg) {
         // 获取参数的理论值和是否为援用
         [$argValue, $argIsRef] = $this->getValueByRef($arg);
         // 创立注入的结构参数
         $argInjects[] = new ArgsInjection($argValue, $argIsRef);
     }
     
     // Set construct inject
     $constructInject = null;
     如果须要注入的结构参数不为空
     if (!empty($argInjects)) {
        // 创立__construct 的注入办法
        $constructInject = new MethodInjection('__construct', $argInjects);
     }
     // 移除结构参数的定义
     // Remove construct definition
     unset($definition[0]);
     // 解析配置中的__option 局部
     // Parse definition option
     $option = $definition['__option'] ?? [];
     if (!is_array($option)) {throw new InvalidArgumentException('__option for definition must be array');
     }
     // 移除__option 的配置
     // Remove `__option`
     unset($definition['__option']);
     // 解析属性配置
     // Parse definition properties
     $propertyInjects = [];
     // 遍历残余的所有配置
     foreach ($definition as $propertyName => $propertyValue) {
         // 如果属性名不是字符串, 则报错
         if (!is_string($propertyName)) {throw new InvalidArgumentException('Property key from definition must be string');
         }
         // 获取属性值和类型
         [$proValue, $proIsRef] = $this->getValueByRef($propertyValue);
         // 如果属性是个数组, 则再次遍历设置
         // Parse property for array
         if (is_array($proValue)) {$proValue = $this->parseArrayProperty($proValue);
         }
         // 创立属性注入对象
         $propertyInject = new PropertyInjection($propertyName, $proValue, $proIsRef);
         // 保留属性注入对象
         $propertyInjects[$propertyName] = $propertyInject;
     }
     return [$constructInject, $propertyInjects, $option];
}

获取参数的理论值和是否援用:

protected function getValueByRef($value): array
{if (!is_string($value)) {return [$value, false];
     }
     // Reg match
     $isRef = preg_match('/^${(.*)}$/', $value, $match);
     if ($isRef && isset($match[1])) {return [$match[1], (bool)$isRef];
     }
     return [$value, false];
}

创立新的定义对象:

private function createObjectDefinition(string $beanName, array $definition): void
{
     // 获取配置中定义的类名, 不存在就报错
     $className = $definition['class'] ?? '';
     if (empty($className)) {throw new InvalidArgumentException(sprintf('%s key for definition must be defined class', $beanName));
     }
     // 通过定义对象名称 (beanName) 和类名实例化新的定义对象
     $objDefinition = new ObjectDefinition($beanName, $className);
     // 更新定义对象
     $objDefinition = $this->updateObjectDefinitionByDefinition($objDefinition, $definition);
     // 将新的定义对象名增加到类名映射数组中
     // 别名在 updateObjectDefinitionByDefinition 办法中曾经更新
     $classNames = $this->classNames[$className] ?? [];
     $classNames[] = $beanName;
     $this->classNames[$className]       = array_unique($classNames);
     // 保留定义对象
     $this->objectDefinitions[$beanName] = $objDefinition;
}

总结:

本大节的次要性能:
    依据 bean 的配置信息, 更新前一大节失去的定义对象, 创立前一大节没有创立的定义对象.
退出移动版