通过上一节的注解解析后,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的配置信息,更新前一大节失去的定义对象,创立前一大节没有创立的定义对象.