Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
| 1 | <?php |
||
| 15 | class ParserBuilder implements ParserBuilderInterface |
||
| 16 | { |
||
| 17 | /** |
||
| 18 | * @var EventDispatcherInterface |
||
| 19 | */ |
||
| 20 | protected $eventDispatcher; |
||
| 21 | |||
| 22 | /** |
||
| 23 | * @var ModifierInterface[] |
||
| 24 | */ |
||
| 25 | protected $modifiers = []; |
||
| 26 | |||
| 27 | /** |
||
| 28 | * @param EventDispatcherInterface $eventDispatcher |
||
| 29 | */ |
||
| 30 | 22 | public function __construct(EventDispatcherInterface $eventDispatcher = null) |
|
| 34 | |||
| 35 | /** |
||
| 36 | * @inheritdoc |
||
| 37 | */ |
||
| 38 | public function getEventDispatcher() |
||
| 42 | |||
| 43 | /** |
||
| 44 | * @return ModifierInterface[] |
||
| 45 | */ |
||
| 46 | 10 | public function getModifiers() |
|
| 50 | |||
| 51 | /** |
||
| 52 | * @param ModifierInterface $modifier |
||
| 53 | * @param int $position Defaults to the next highest position |
||
| 54 | * @param bool $continue Will be determined based on modifier type |
||
| 55 | * |
||
| 56 | * @throws \InvalidArgumentException If there already is a modifier at the given position |
||
| 57 | */ |
||
| 58 | 16 | View Code Duplication | public function addModifier(ModifierInterface $modifier, $position = null, $continue = null) |
|
|
|||
| 59 | { |
||
| 60 | 16 | if (null === $position) { |
|
| 61 | 10 | $position = sizeof($this->modifiers) ? (max(array_keys($this->modifiers)) + 1) : 0; |
|
| 62 | } |
||
| 63 | |||
| 64 | 16 | if (null === $continue) { |
|
| 65 | 14 | $continue = (!$modifier instanceof FilterInterface) && (!$modifier instanceof ValidatorInterface); |
|
| 66 | } |
||
| 67 | |||
| 68 | 16 | if (array_key_exists($position, $this->modifiers)) { |
|
| 69 | 2 | throw new \InvalidArgumentException(sprintf('There already is a modifier at position %d', $position)); |
|
| 70 | } |
||
| 71 | |||
| 72 | 16 | $this->modifiers[$position] = [$modifier, $continue]; |
|
| 73 | 16 | } |
|
| 74 | |||
| 75 | /** |
||
| 76 | * Adds the given modifier between the start and end index, if there is a vacant position. |
||
| 77 | * |
||
| 78 | * @param ModifierInterface $modifier |
||
| 79 | * @param int $startIndex |
||
| 80 | * @param int $endIndex |
||
| 81 | * @param bool $continue |
||
| 82 | * |
||
| 83 | * @throws \OutOfBoundsException |
||
| 84 | */ |
||
| 85 | View Code Duplication | public function addModifierBetween(ModifierInterface $modifier, $startIndex, $endIndex, $continue = null) |
|
| 86 | { |
||
| 87 | for ($position = $startIndex; $position <= $endIndex; ++$position) { |
||
| 88 | if (!$this->hasModifierAt($position)) { |
||
| 89 | $this->addModifier($modifier, $position, $continue); |
||
| 90 | |||
| 91 | return; |
||
| 92 | } |
||
| 93 | } |
||
| 94 | |||
| 95 | throw new \OutOfBoundsException(sprintf('No position left between %d and %d', $startIndex, $endIndex)); |
||
| 96 | } |
||
| 97 | |||
| 98 | /** |
||
| 99 | * Shortcut for adding a field-value transformer. |
||
| 100 | * |
||
| 101 | * @param TransformerInterface $transformer |
||
| 102 | * @param string $field |
||
| 103 | * @param int $position |
||
| 104 | * @param bool $continue |
||
| 105 | */ |
||
| 106 | 2 | public function addTransformer(TransformerInterface $transformer, $field, $position = null, $continue = true) |
|
| 110 | |||
| 111 | /** |
||
| 112 | * Adds the given transformer between the start and end index, if there is a vacant position. |
||
| 113 | * |
||
| 114 | * @param TransformerInterface $transformer |
||
| 115 | * @param string $field |
||
| 116 | * @param int $startIndex |
||
| 117 | * @param int $endIndex |
||
| 118 | * @param bool $continue |
||
| 119 | * |
||
| 120 | * @throws \OutOfBoundsException |
||
| 121 | */ |
||
| 122 | public function addTransformerBetween(TransformerInterface $transformer, $field, $startIndex, $endIndex, $continue = null) |
||
| 126 | |||
| 127 | /** |
||
| 128 | * @param int $position |
||
| 129 | * |
||
| 130 | * @return bool |
||
| 131 | */ |
||
| 132 | public function hasModifierAt($position) |
||
| 136 | |||
| 137 | /** |
||
| 138 | * Removes existing modifier. |
||
| 139 | * |
||
| 140 | * @param ModifierInterface $modifier |
||
| 141 | */ |
||
| 142 | 2 | View Code Duplication | public function removeModifier(ModifierInterface $modifier) |
| 143 | { |
||
| 144 | 2 | foreach ($this->modifiers as $position => list($mod)) { |
|
| 145 | 2 | if ($mod === $modifier) { |
|
| 146 | 2 | unset($this->modifiers[$position]); |
|
| 147 | } |
||
| 148 | } |
||
| 149 | 2 | } |
|
| 150 | |||
| 151 | /** |
||
| 152 | * Removes modifier at an existing position. |
||
| 153 | * |
||
| 154 | * @param int $position |
||
| 155 | * |
||
| 156 | * @throws \OutOfBoundsException If modifier does not exist |
||
| 157 | */ |
||
| 158 | 4 | View Code Duplication | public function removeModifierAt($position) |
| 166 | |||
| 167 | /** |
||
| 168 | * @inheritdoc |
||
| 169 | */ |
||
| 170 | 6 | public function build(ParserTypeInterface $type, array $options) |
|
| 171 | { |
||
| 172 | 6 | $resolver = $this->getOptionsResolver($type); |
|
| 173 | |||
| 174 | 6 | $type->build($this, $resolver->resolve($options)); |
|
| 175 | |||
| 176 | 6 | $parser = new DefaultParser($this->eventDispatcher); |
|
| 177 | 6 | foreach ($this->modifiers as $position => list($modifier, $continue)) { |
|
| 178 | 2 | $parser->addModifier($modifier, $position, $continue); |
|
| 179 | } |
||
| 180 | |||
| 181 | 6 | return $parser; |
|
| 182 | } |
||
| 183 | |||
| 184 | /** |
||
| 185 | * @param ParserTypeInterface $type |
||
| 186 | * |
||
| 187 | * @return OptionsResolver |
||
| 188 | */ |
||
| 189 | 6 | protected function getOptionsResolver(ParserTypeInterface $type) |
|
| 196 | } |
||
| 197 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.