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