4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\DependencyInjection\Compiler;
14 use Symfony\Component\DependencyInjection\ContainerBuilder;
15 use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
18 * Checks your services for circular references.
20 * References from method calls are ignored since we might be able to resolve
21 * these references depending on the order in which services are called.
23 * Circular reference from method calls will only be detected at run-time.
25 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
27 class CheckCircularReferencesPass implements CompilerPassInterface
30 private $checkedNodes;
33 * Checks the ContainerBuilder object for circular references.
35 public function process(ContainerBuilder $container)
37 $graph = $container->getCompiler()->getServiceReferenceGraph();
39 $this->checkedNodes = array();
40 foreach ($graph->getNodes() as $id => $node) {
41 $this->currentPath = array($id);
43 $this->checkOutEdges($node->getOutEdges());
48 * Checks for circular references.
50 * @param ServiceReferenceGraphEdge[] $edges An array of Edges
52 * @throws ServiceCircularReferenceException when a circular reference is found
54 private function checkOutEdges(array $edges)
56 foreach ($edges as $edge) {
57 $node = $edge->getDestNode();
60 if (empty($this->checkedNodes[$id])) {
61 // Don't check circular references for lazy edges
62 if (!$node->getValue() || (!$edge->isLazy() && !$edge->isWeak())) {
63 $searchKey = array_search($id, $this->currentPath);
64 $this->currentPath[] = $id;
66 if (false !== $searchKey) {
67 throw new ServiceCircularReferenceException($id, \array_slice($this->currentPath, $searchKey));
70 $this->checkOutEdges($node->getOutEdges());
73 $this->checkedNodes[$id] = true;
74 array_pop($this->currentPath);