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 |
||
10 | final class Configurator |
||
11 | { |
||
12 | const SETTING_PREFIX = 'config_prefix'; |
||
13 | const SETTING_SEPARATOR = 'config_separator'; |
||
14 | const SETTING_SERVICES_KEY = 'services_key'; |
||
15 | const SETTING_INFLECTORS_KEY = 'inflectors_key'; |
||
16 | const SETTING_DEFAULT_SINGLETON_SERVICES = 'default_singleton_services'; |
||
17 | |||
18 | const FILE_READERS = [ |
||
19 | '.json' => FileReader\JSONFileReader::class, |
||
20 | '.php' => FileReader\PHPFileReader::class, |
||
21 | '.yaml' => FileReader\YAMLFileReader::class, |
||
22 | '.yml' => FileReader\YAMLFileReader::class, |
||
23 | ]; |
||
24 | |||
25 | const CONTAINER_ADAPTERS = [ |
||
26 | \League\Container\Container::class => League\LeagueContainerAdapter::class, |
||
27 | \Pimple\Container::class => Pimple\PimpleContainerAdapter::class, |
||
28 | ]; |
||
29 | |||
30 | /** |
||
31 | * @var ApplicationConfig |
||
32 | */ |
||
33 | private $config; |
||
34 | |||
35 | /** |
||
36 | * @var FileReader\ReaderFactory |
||
37 | */ |
||
38 | private $readerFactory; |
||
39 | |||
40 | /** |
||
41 | * @var mixed[] |
||
42 | */ |
||
43 | private $settings = [ |
||
44 | self::SETTING_PREFIX => 'config', |
||
45 | self::SETTING_SEPARATOR => '.', |
||
46 | self::SETTING_SERVICES_KEY => 'di.services', |
||
47 | self::SETTING_INFLECTORS_KEY => 'di.inflectors', |
||
48 | self::SETTING_DEFAULT_SINGLETON_SERVICES => false, |
||
49 | ]; |
||
50 | |||
51 | /** |
||
52 | * @var string[] |
||
53 | */ |
||
54 | private $fileReaders = self::FILE_READERS; |
||
55 | |||
56 | /** |
||
57 | * @var string[] |
||
58 | */ |
||
59 | private $containerAdapters = self::CONTAINER_ADAPTERS; |
||
60 | |||
61 | /** |
||
62 | * @var string |
||
63 | */ |
||
64 | private static $containerIdentifier; |
||
65 | |||
66 | /** |
||
67 | * @return Configurator |
||
68 | */ |
||
69 | public static function apply() |
||
70 | { |
||
71 | return new self(); |
||
72 | } |
||
73 | |||
74 | private function __construct() |
||
75 | { |
||
76 | $this->config = new ApplicationConfig([]); |
||
77 | } |
||
78 | |||
79 | /** |
||
80 | * @return string |
||
81 | */ |
||
82 | public static function container() |
||
83 | { |
||
84 | if (!self::$containerIdentifier) { |
||
85 | self::$containerIdentifier = uniqid(__CLASS__ . '::CONTAINER_ID::'); |
||
86 | } |
||
87 | |||
88 | return self::$containerIdentifier; |
||
89 | } |
||
90 | |||
91 | /** |
||
92 | * @param array $config |
||
93 | * |
||
94 | * @return $this |
||
95 | */ |
||
96 | public function configFromArray(array $config) |
||
97 | { |
||
98 | $this->config->merge($config); |
||
99 | |||
100 | return $this; |
||
101 | } |
||
102 | |||
103 | /** |
||
104 | * @param string $filename |
||
105 | * |
||
106 | * @throws InvalidArgumentException |
||
107 | * |
||
108 | * @return $this |
||
109 | */ |
||
110 | public function configFromFile($filename) |
||
111 | { |
||
112 | Assertion::file($filename); |
||
113 | |||
114 | $this->readFileAndMergeConfig($filename); |
||
115 | |||
116 | return $this; |
||
117 | } |
||
118 | |||
119 | /** |
||
120 | * @param string $pattern |
||
121 | * |
||
122 | * @throws NoMatchingFilesException |
||
123 | * @throws InvalidArgumentException |
||
124 | * |
||
125 | * @return $this |
||
126 | */ |
||
127 | public function configFromFiles($pattern) |
||
128 | { |
||
129 | Assertion::string($pattern); |
||
130 | |||
131 | $locator = new FileReader\FileLocator(); |
||
132 | |||
133 | $files = $locator->locate($pattern); |
||
134 | |||
135 | if (count($files) === 0) { |
||
136 | throw NoMatchingFilesException::fromPattern($pattern); |
||
137 | } |
||
138 | |||
139 | foreach ($files as $filename) { |
||
140 | $this->readFileAndMergeConfig($filename); |
||
141 | } |
||
142 | |||
143 | return $this; |
||
144 | } |
||
145 | |||
146 | /** |
||
147 | * @param string $name |
||
148 | * @param mixed $value |
||
149 | * |
||
150 | * @throws UnknownSettingException |
||
151 | * @throws InvalidArgumentException |
||
152 | * |
||
153 | * @return $this |
||
154 | */ |
||
155 | public function withSetting($name, $value) |
||
168 | |||
169 | /** |
||
170 | * @param string $extension |
||
171 | * @param string $className |
||
172 | * |
||
173 | * @return $this |
||
174 | */ |
||
175 | public function withFileReader($extension, $className) |
||
181 | |||
182 | /** |
||
183 | * @param string $containerName |
||
184 | * @param string $adapterName |
||
185 | * |
||
186 | * @return $this |
||
187 | */ |
||
188 | public function withContainerAdapter($containerName, $adapterName) |
||
194 | |||
195 | /** |
||
196 | * @param object $container |
||
197 | * |
||
198 | * @return void |
||
199 | */ |
||
200 | public function to($container) |
||
223 | |||
224 | /** |
||
225 | * @param string $filename |
||
226 | * |
||
227 | * @return void |
||
228 | */ |
||
229 | private function readFileAndMergeConfig($filename) |
||
235 | |||
236 | /** |
||
237 | * @param string $filename |
||
238 | * |
||
239 | * @return FileReader\FileReader |
||
240 | */ |
||
241 | private function getReaderFor($filename) |
||
249 | } |
||
250 |
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.