(3) Writing PHP container from scratch - solving class duplicate dependency creation
Function realization
- Solve class duplicate dependency creation, solve interdependence (a - > b - > A - > b - > etc.), circular dependency (a - > b - > C - > A - > b - > C - > A - > A - > b - > C - > A - > A - > etc.)
code implementation Container
/** * Resolve interdependence and circular dependency judgment * @param string $abstract * @param array $tmp * @return Closure|object * @throws ReflectionException */ public function createObjectNoEach(string $abstract, array $tmp = []) { if ($tmpInstance = &$tmp[$abstract]) { return $tmpInstance; } $refClass = new ReflectionClass($abstract); if ($refClass->getName() === Closure::class) { return function (){}; } elseif ($refClass->hasMethod('__construct')) { $_constructParams = array_map(function (ReflectionParameter $param) use ($abstract, $tmp) { if ($param->getClass()) { if (array_key_exists($param->getClass()->getName(), $tmp)) { throw new class('can not create a circular dependencies class object.') extends Exception implements ContainerExceptionInterface{ }; } return $this->createObjectNoEach($param->getClass()->getName(), $tmp); } elseif ($param->isDefaultValueAvailable()) { return $param->getDefaultValue(); } elseif ($param->getType()) { return [ 'string' => '', 'int' => 0, 'array' => [], 'bool' => false, 'float' => 0.0, 'iterable' => [], 'callable' => function() {} ][$param->getType()->getName()] ?? null; } else { return null; } }, $refClass->getMethod('__construct')->getParameters()); } return $tmpInstance = $refClass->newInstance(... ($_constructParams ?? [])); }
Implementation ideas
- Automatically create an instance object through storage, judge it as a loop when the same class appears in the parameter list and throw an exception
Add code
- Determine whether the instance object is cached
if ($tmpInstance = &$tmp[$abstract]) { return $tmpInstance; }
- Determine whether the automatically created class has been created. If it has been created, it will be considered as recursion and an exception will be thrown
if (array_key_exists($param->getClass()->getName(), $tmp)) { throw new class('can not create a circular dependencies class object.') extends Exception implements ContainerExceptionInterface{ }; } return $this->createObjectNoEach($param->getClass()->getName(), $tmp);
- Store automatically created class instances
return $tmpInstance = $refClass->newInstance(... ($_constructParams ?? []));