CheckArgumentsValidityPass.php 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\DependencyInjection\Compiler;
  11. use Symfony\Component\DependencyInjection\Definition;
  12. use Symfony\Component\DependencyInjection\Exception\RuntimeException;
  13. /**
  14. * Checks if arguments of methods are properly configured.
  15. *
  16. * @author Kévin Dunglas <dunglas@gmail.com>
  17. * @author Nicolas Grekas <p@tchwork.com>
  18. */
  19. class CheckArgumentsValidityPass extends AbstractRecursivePass
  20. {
  21. private $throwExceptions;
  22. public function __construct(bool $throwExceptions = true)
  23. {
  24. $this->throwExceptions = $throwExceptions;
  25. }
  26. /**
  27. * {@inheritdoc}
  28. */
  29. protected function processValue($value, bool $isRoot = false)
  30. {
  31. if (!$value instanceof Definition) {
  32. return parent::processValue($value, $isRoot);
  33. }
  34. $i = 0;
  35. $hasNamedArgs = false;
  36. foreach ($value->getArguments() as $k => $v) {
  37. if (\PHP_VERSION_ID >= 80000 && preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $k)) {
  38. $hasNamedArgs = true;
  39. continue;
  40. }
  41. if ($k !== $i++) {
  42. if (!\is_int($k)) {
  43. $msg = sprintf('Invalid constructor argument for service "%s": integer expected but found string "%s". Check your service definition.', $this->currentId, $k);
  44. $value->addError($msg);
  45. if ($this->throwExceptions) {
  46. throw new RuntimeException($msg);
  47. }
  48. break;
  49. }
  50. $msg = sprintf('Invalid constructor argument %d for service "%s": argument %d must be defined before. Check your service definition.', 1 + $k, $this->currentId, $i);
  51. $value->addError($msg);
  52. if ($this->throwExceptions) {
  53. throw new RuntimeException($msg);
  54. }
  55. }
  56. if ($hasNamedArgs) {
  57. $msg = sprintf('Invalid constructor argument for service "%s": cannot use positional argument after named argument. Check your service definition.', $this->currentId);
  58. $value->addError($msg);
  59. if ($this->throwExceptions) {
  60. throw new RuntimeException($msg);
  61. }
  62. break;
  63. }
  64. }
  65. foreach ($value->getMethodCalls() as $methodCall) {
  66. $i = 0;
  67. $hasNamedArgs = false;
  68. foreach ($methodCall[1] as $k => $v) {
  69. if (\PHP_VERSION_ID >= 80000 && preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $k)) {
  70. $hasNamedArgs = true;
  71. continue;
  72. }
  73. if ($k !== $i++) {
  74. if (!\is_int($k)) {
  75. $msg = sprintf('Invalid argument for method call "%s" of service "%s": integer expected but found string "%s". Check your service definition.', $methodCall[0], $this->currentId, $k);
  76. $value->addError($msg);
  77. if ($this->throwExceptions) {
  78. throw new RuntimeException($msg);
  79. }
  80. break;
  81. }
  82. $msg = sprintf('Invalid argument %d for method call "%s" of service "%s": argument %d must be defined before. Check your service definition.', 1 + $k, $methodCall[0], $this->currentId, $i);
  83. $value->addError($msg);
  84. if ($this->throwExceptions) {
  85. throw new RuntimeException($msg);
  86. }
  87. }
  88. if ($hasNamedArgs) {
  89. $msg = sprintf('Invalid argument for method call "%s" of service "%s": cannot use positional argument after named argument. Check your service definition.', $methodCall[0], $this->currentId);
  90. $value->addError($msg);
  91. if ($this->throwExceptions) {
  92. throw new RuntimeException($msg);
  93. }
  94. break;
  95. }
  96. }
  97. }
  98. return null;
  99. }
  100. }