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 |
||
33 | class OLERead |
||
34 | { |
||
35 | private $data = ''; |
||
36 | |||
37 | // OLE identifier |
||
38 | const IDENTIFIER_OLE = IDENTIFIER_OLE; |
||
39 | |||
40 | // Size of a sector = 512 bytes |
||
41 | const BIG_BLOCK_SIZE = 0x200; |
||
42 | |||
43 | // Size of a short sector = 64 bytes |
||
44 | const SMALL_BLOCK_SIZE = 0x40; |
||
45 | |||
46 | // Size of a directory entry always = 128 bytes |
||
47 | const PROPERTY_STORAGE_BLOCK_SIZE = 0x80; |
||
48 | |||
49 | // Minimum size of a standard stream = 4096 bytes, streams smaller than this are stored as short streams |
||
50 | const SMALL_BLOCK_THRESHOLD = 0x1000; |
||
51 | |||
52 | // header offsets |
||
53 | const NUM_BIG_BLOCK_DEPOT_BLOCKS_POS = 0x2c; |
||
54 | const ROOT_START_BLOCK_POS = 0x30; |
||
55 | const SMALL_BLOCK_DEPOT_BLOCK_POS = 0x3c; |
||
56 | const EXTENSION_BLOCK_POS = 0x44; |
||
57 | const NUM_EXTENSION_BLOCK_POS = 0x48; |
||
58 | const BIG_BLOCK_DEPOT_BLOCKS_POS = 0x4c; |
||
59 | |||
60 | // property storage offsets (directory offsets) |
||
61 | const SIZE_OF_NAME_POS = 0x40; |
||
62 | const TYPE_POS = 0x42; |
||
63 | const START_BLOCK_POS = 0x74; |
||
64 | const SIZE_POS = 0x78; |
||
65 | |||
66 | public $wrkbook = null; |
||
67 | public $summaryInformation = null; |
||
68 | public $documentSummaryInformation = null; |
||
69 | |||
70 | /** |
||
71 | * Read the file |
||
72 | * |
||
73 | * @param $sFileName string Filename |
||
74 | * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception |
||
75 | */ |
||
76 | 4 | public function read($sFileName) |
|
77 | { |
||
78 | // Check if file exists and is readable |
||
79 | 4 | if (!is_readable($sFileName)) { |
|
80 | throw new \PhpOffice\PhpSpreadsheet\Reader\Exception('Could not open ' . $sFileName . ' for reading! File does not exist, or it is not readable.'); |
||
81 | } |
||
82 | |||
83 | // Get the file identifier |
||
84 | // Don't bother reading the whole file until we know it's a valid OLE file |
||
85 | 4 | $this->data = file_get_contents($sFileName, false, null, 0, 8); |
|
86 | |||
87 | // Check OLE identifier |
||
88 | 4 | if ($this->data != self::IDENTIFIER_OLE) { |
|
89 | throw new \PhpOffice\PhpSpreadsheet\Reader\Exception('The filename ' . $sFileName . ' is not recognised as an OLE file'); |
||
90 | } |
||
91 | |||
92 | // Get the file data |
||
93 | 4 | $this->data = file_get_contents($sFileName); |
|
94 | |||
95 | // Total number of sectors used for the SAT |
||
96 | 4 | $this->numBigBlockDepotBlocks = self::getInt4d($this->data, self::NUM_BIG_BLOCK_DEPOT_BLOCKS_POS); |
|
97 | |||
98 | // SecID of the first sector of the directory stream |
||
99 | 4 | $this->rootStartBlock = self::getInt4d($this->data, self::ROOT_START_BLOCK_POS); |
|
100 | |||
101 | // SecID of the first sector of the SSAT (or -2 if not extant) |
||
102 | 4 | $this->sbdStartBlock = self::getInt4d($this->data, self::SMALL_BLOCK_DEPOT_BLOCK_POS); |
|
103 | |||
104 | // SecID of the first sector of the MSAT (or -2 if no additional sectors are used) |
||
105 | 4 | $this->extensionBlock = self::getInt4d($this->data, self::EXTENSION_BLOCK_POS); |
|
106 | |||
107 | // Total number of sectors used by MSAT |
||
108 | 4 | $this->numExtensionBlocks = self::getInt4d($this->data, self::NUM_EXTENSION_BLOCK_POS); |
|
109 | |||
110 | 4 | $bigBlockDepotBlocks = []; |
|
111 | 4 | $pos = self::BIG_BLOCK_DEPOT_BLOCKS_POS; |
|
112 | |||
113 | 4 | $bbdBlocks = $this->numBigBlockDepotBlocks; |
|
114 | |||
115 | 4 | if ($this->numExtensionBlocks != 0) { |
|
116 | $bbdBlocks = (self::BIG_BLOCK_SIZE - self::BIG_BLOCK_DEPOT_BLOCKS_POS) / 4; |
||
117 | } |
||
118 | |||
119 | 4 | View Code Duplication | for ($i = 0; $i < $bbdBlocks; ++$i) { |
120 | 4 | $bigBlockDepotBlocks[$i] = self::getInt4d($this->data, $pos); |
|
121 | 4 | $pos += 4; |
|
122 | } |
||
123 | |||
124 | 4 | for ($j = 0; $j < $this->numExtensionBlocks; ++$j) { |
|
125 | $pos = ($this->extensionBlock + 1) * self::BIG_BLOCK_SIZE; |
||
126 | $blocksToRead = min($this->numBigBlockDepotBlocks - $bbdBlocks, self::BIG_BLOCK_SIZE / 4 - 1); |
||
127 | |||
128 | View Code Duplication | for ($i = $bbdBlocks; $i < $bbdBlocks + $blocksToRead; ++$i) { |
|
129 | $bigBlockDepotBlocks[$i] = self::getInt4d($this->data, $pos); |
||
130 | $pos += 4; |
||
131 | } |
||
132 | |||
133 | $bbdBlocks += $blocksToRead; |
||
134 | if ($bbdBlocks < $this->numBigBlockDepotBlocks) { |
||
135 | $this->extensionBlock = self::getInt4d($this->data, $pos); |
||
136 | } |
||
137 | } |
||
138 | |||
139 | 4 | $pos = 0; |
|
140 | 4 | $this->bigBlockChain = ''; |
|
141 | 4 | $bbs = self::BIG_BLOCK_SIZE / 4; |
|
142 | 4 | for ($i = 0; $i < $this->numBigBlockDepotBlocks; ++$i) { |
|
143 | 4 | $pos = ($bigBlockDepotBlocks[$i] + 1) * self::BIG_BLOCK_SIZE; |
|
144 | |||
145 | 4 | $this->bigBlockChain .= substr($this->data, $pos, 4 * $bbs); |
|
146 | 4 | $pos += 4 * $bbs; |
|
147 | } |
||
148 | |||
149 | 4 | $pos = 0; |
|
150 | 4 | $sbdBlock = $this->sbdStartBlock; |
|
151 | 4 | $this->smallBlockChain = ''; |
|
152 | 4 | while ($sbdBlock != -2) { |
|
153 | 4 | $pos = ($sbdBlock + 1) * self::BIG_BLOCK_SIZE; |
|
154 | |||
155 | 4 | $this->smallBlockChain .= substr($this->data, $pos, 4 * $bbs); |
|
156 | 4 | $pos += 4 * $bbs; |
|
157 | |||
158 | 4 | $sbdBlock = self::getInt4d($this->bigBlockChain, $sbdBlock * 4); |
|
159 | } |
||
160 | |||
161 | // read the directory stream |
||
162 | 4 | $block = $this->rootStartBlock; |
|
163 | 4 | $this->entry = $this->_readData($block); |
|
164 | |||
165 | 4 | $this->readPropertySets(); |
|
166 | 4 | } |
|
167 | |||
168 | /** |
||
169 | * Extract binary stream data |
||
170 | * |
||
171 | * @param int $stream |
||
172 | * @return string |
||
173 | */ |
||
174 | 4 | public function getStream($stream) |
|
216 | |||
217 | /** |
||
218 | * Read a standard stream (by joining sectors using information from SAT) |
||
219 | * |
||
220 | * @param int $bl Sector ID where the stream starts |
||
221 | * @return string Data for standard stream |
||
222 | */ |
||
223 | 4 | private function _readData($bl) |
|
236 | |||
237 | /** |
||
238 | * Read entries in the directory stream. |
||
239 | */ |
||
240 | 4 | private function readPropertySets() |
|
295 | |||
296 | /** |
||
297 | * Read 4 bytes of data at specified position |
||
298 | * |
||
299 | * @param string $data |
||
300 | * @param int $pos |
||
301 | * @return int |
||
302 | */ |
||
303 | 4 | private static function getInt4d($data, $pos) |
|
331 | } |
||
332 |
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.