Complex classes like ReadOnlyFallbackAdapter often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use ReadOnlyFallbackAdapter, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
9 | class ReadOnlyFallbackAdapter implements AdapterInterface |
||
10 | { |
||
11 | protected $_readOnlyAdapter; |
||
12 | |||
13 | protected $_mainAdapter; |
||
14 | |||
15 | public function __construct(AdapterInterface $mainAdapter, AdapterInterface $readOnlyAdapter) |
||
20 | |||
21 | /** |
||
22 | * Returns the main adapter |
||
23 | * |
||
24 | * @return AdapterInterface |
||
25 | */ |
||
26 | public function getMainAdapter() |
||
30 | |||
31 | /** |
||
32 | * Returns the fallback adapter |
||
33 | * |
||
34 | * @return AdapterInterface |
||
35 | */ |
||
36 | public function getReadOnlyAdapter() |
||
37 | 2 | { |
|
38 | 2 | return $this->_readOnlyAdapter; |
|
39 | } |
||
40 | |||
41 | /** |
||
42 | * {@inheritdoc} |
||
43 | */ |
||
44 | public function write($path, $contents, Config $config) |
||
45 | 2 | { |
|
46 | 2 | return $this->_mainAdapter->write($path, $contents, $config); |
|
47 | } |
||
48 | |||
49 | /** |
||
50 | * {@inheritdoc} |
||
51 | */ |
||
52 | public function writeStream($path, $resource, Config $config) |
||
53 | { |
||
54 | 2 | return $this->_mainAdapter->writeStream($path, $resource, $config); |
|
55 | } |
||
56 | |||
57 | /** |
||
58 | * {@inheritdoc} |
||
59 | */ |
||
60 | public function update($path, $contents, Config $config) |
||
61 | { |
||
62 | 2 | $this->_backportFromReadOnly($path); |
|
63 | |||
64 | 2 | return $this->_mainAdapter->update($path, $contents, $config); |
|
65 | } |
||
66 | |||
67 | /** |
||
68 | * {@inheritdoc} |
||
69 | */ |
||
70 | public function updateStream($path, $resource, Config $config) |
||
76 | |||
77 | /** |
||
78 | * {@inheritdoc} |
||
79 | */ |
||
80 | public function rename($path, $newpath) |
||
81 | { |
||
82 | // XXX we could probably make some improvements here without duplicate the source |
||
83 | $this->_backportFromReadOnly($path); |
||
84 | |||
85 | 2 | return $this->_mainAdapter->rename($path, $newpath); |
|
86 | } |
||
87 | |||
88 | /** |
||
89 | * {@inheritdoc} |
||
90 | */ |
||
91 | public function copy($path, $newpath) |
||
98 | |||
99 | /** |
||
100 | * {@inheritdoc} |
||
101 | */ |
||
102 | public function delete($path) |
||
103 | { |
||
104 | 2 | if ($this->_readOnlyAdapter->has($path) && !$this->_mainAdapter->has($path)) |
|
105 | 2 | { |
|
106 | // will always be find but yeah except if we have an adapter that retains the delete information, it's impossible to |
||
107 | // do something. So enjoy a weird thing |
||
108 | 2 | return true; |
|
109 | } |
||
110 | |||
111 | 2 | return $this->_mainAdapter->delete($path); |
|
112 | } |
||
113 | |||
114 | /** |
||
115 | * {@inheritdoc} |
||
116 | */ |
||
117 | public function deleteDir($dirname) |
||
126 | |||
127 | /** |
||
128 | * {@inheritdoc} |
||
129 | */ |
||
130 | public function createDir($dirname, Config $config) |
||
134 | |||
135 | /** |
||
136 | * {@inheritdoc} |
||
137 | */ |
||
138 | public function setVisibility($path, $visibility) |
||
144 | |||
145 | /** |
||
146 | * {@inheritdoc} |
||
147 | */ |
||
148 | public function has($path) |
||
152 | |||
153 | /** |
||
154 | * {@inheritdoc} |
||
155 | */ |
||
156 | public function read($path) |
||
157 | { |
||
158 | 2 | if ($this->_mainAdapter->has($path)) |
|
166 | |||
167 | /** |
||
168 | * {@inheritdoc} |
||
169 | */ |
||
170 | public function readStream($path) |
||
179 | |||
180 | //TODO |
||
181 | /** |
||
182 | * {@inheritdoc} |
||
183 | * @see https://github.com/Litipk/flysystem-fallback-adapter/blob/master/src/FallbackAdapter.php#L259 |
||
184 | */ |
||
185 | public function listContents($directory = '', $recursive = false) |
||
208 | |||
209 | /** |
||
210 | * {@inheritdoc} |
||
211 | */ |
||
212 | public function getMetadata($path) |
||
221 | |||
222 | /** |
||
223 | * {@inheritdoc} |
||
224 | */ |
||
225 | public function getSize($path) |
||
234 | |||
235 | /** |
||
236 | * {@inheritdoc} |
||
237 | */ |
||
238 | public function getMimetype($path) |
||
247 | |||
248 | /** |
||
249 | * {@inheritdoc} |
||
250 | */ |
||
251 | public function getTimestamp($path) |
||
260 | |||
261 | /** |
||
262 | * {@inheritdoc} |
||
263 | */ |
||
264 | public function getVisibility($path) |
||
273 | |||
274 | /** |
||
275 | * Make resource available for modification on the new adapter |
||
276 | * @param string $path |
||
277 | * @return bool |
||
278 | */ |
||
279 | protected function _backportFromReadOnly($path) |
||
302 | } |
||
303 |
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.
Unreachable code is most often the result of
return
,die
orexit
statements that have been added for debug purposes.In the above example, the last
return false
will never be executed, because a return statement has already been met in every possible execution path.