CheckCircularReferencesPass.php 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. <?php
  2. namespace Symfony\Component\DependencyInjection\Compiler;
  3. use Symfony\Component\DependencyInjection\Exception\CircularReferenceException;
  4. use Symfony\Component\DependencyInjection\ContainerBuilder;
  5. /**
  6. * Checks your services for circular references
  7. *
  8. * References from method calls are ignored since we might be able to resolve
  9. * these references depending on the order in which services are called.
  10. *
  11. * Circular reference from method calls will only be detected at run-time.
  12. *
  13. * @author Johannes M. Schmitt <schmittjoh@gmail.com>
  14. */
  15. class CheckCircularReferencesPass implements CompilerPassInterface
  16. {
  17. private $currentId;
  18. private $currentNode;
  19. private $currentPath;
  20. /**
  21. * Checks the ContainerBuilder object for circular references.
  22. *
  23. * @param ContainerBuilder $container The ContainerBuilder instances
  24. */
  25. public function process(ContainerBuilder $container)
  26. {
  27. $graph = $container->getCompiler()->getServiceReferenceGraph();
  28. foreach ($graph->getNodes() as $id => $node) {
  29. $this->currentId = $id;
  30. $this->currentPath = array($id);
  31. $this->checkOutEdges($node->getOutEdges());
  32. }
  33. }
  34. /**
  35. * Checks for circular references.
  36. *
  37. * @param array $edges An array of Nodes
  38. * @throws \RuntimeException When a circular reference is found.
  39. */
  40. private function checkOutEdges(array $edges)
  41. {
  42. foreach ($edges as $edge) {
  43. $node = $edge->getDestNode();
  44. $this->currentPath[] = $id = $node->getId();
  45. if ($this->currentId === $id) {
  46. throw new CircularReferenceException($this->currentId, $this->currentPath);
  47. }
  48. $this->checkOutEdges($node->getOutEdges());
  49. array_pop($this->currentPath);
  50. }
  51. }
  52. }