| Total Complexity | 49 |
| Total Lines | 175 |
| Duplicated Lines | 0 % |
| Changes | 0 | ||
Complex classes like MaskPatternTester 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.
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 MaskPatternTester, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 25 | final class MaskPatternTester{ |
||
| 26 | |||
| 27 | /** |
||
| 28 | * The data interface that contains the data matrix to test |
||
| 29 | */ |
||
| 30 | private QRData $qrData; |
||
| 31 | |||
| 32 | /** |
||
| 33 | * Receives the QRData object |
||
| 34 | * |
||
| 35 | * @see \chillerlan\QRCode\QROptions::$maskPattern |
||
| 36 | * @see \chillerlan\QRCode\Data\QRMatrix::$maskPattern |
||
| 37 | */ |
||
| 38 | public function __construct(QRData $qrData){ |
||
| 39 | $this->qrData = $qrData; |
||
| 40 | } |
||
| 41 | |||
| 42 | /** |
||
| 43 | * shoves a QRMatrix through the MaskPatternTester to find the lowest penalty mask pattern |
||
| 44 | * |
||
| 45 | * @see \chillerlan\QRCode\Data\MaskPatternTester |
||
| 46 | */ |
||
| 47 | public function getBestMaskPattern():MaskPattern{ |
||
| 48 | $penalties = []; |
||
| 49 | |||
| 50 | foreach(MaskPattern::PATTERNS as $pattern){ |
||
| 51 | $penalties[$pattern] = $this->testPattern(new MaskPattern($pattern)); |
||
| 52 | } |
||
| 53 | |||
| 54 | return new MaskPattern(array_search(min($penalties), $penalties, true)); |
||
|
|
|||
| 55 | } |
||
| 56 | |||
| 57 | /** |
||
| 58 | * Returns the penalty for the given mask pattern |
||
| 59 | * |
||
| 60 | * @see \chillerlan\QRCode\QROptions::$maskPattern |
||
| 61 | * @see \chillerlan\QRCode\Data\QRMatrix::$maskPattern |
||
| 62 | */ |
||
| 63 | public function testPattern(MaskPattern $pattern):int{ |
||
| 64 | $matrix = $this->qrData->writeMatrix($pattern, true); |
||
| 65 | $penalty = 0; |
||
| 66 | |||
| 67 | for($level = 1; $level <= 4; $level++){ |
||
| 68 | $penalty += call_user_func_array([$this, 'testLevel'.$level], [$matrix->matrix(true), $matrix->size()]); |
||
| 69 | } |
||
| 70 | |||
| 71 | return (int)$penalty; |
||
| 72 | } |
||
| 73 | |||
| 74 | /** |
||
| 75 | * Checks for each group of five or more same-colored modules in a row (or column) |
||
| 76 | */ |
||
| 77 | private function testLevel1(array $m, int $size):int{ |
||
| 78 | $penalty = 0; |
||
| 79 | |||
| 80 | foreach($m as $y => $row){ |
||
| 81 | foreach($row as $x => $val){ |
||
| 82 | $count = 0; |
||
| 83 | |||
| 84 | for($ry = -1; $ry <= 1; $ry++){ |
||
| 85 | |||
| 86 | if($y + $ry < 0 || $size <= $y + $ry){ |
||
| 87 | continue; |
||
| 88 | } |
||
| 89 | |||
| 90 | for($rx = -1; $rx <= 1; $rx++){ |
||
| 91 | |||
| 92 | if(($ry === 0 && $rx === 0) || (($x + $rx) < 0 || $size <= ($x + $rx))){ |
||
| 93 | continue; |
||
| 94 | } |
||
| 95 | |||
| 96 | if($m[$y + $ry][$x + $rx] === $val){ |
||
| 97 | $count++; |
||
| 98 | } |
||
| 99 | |||
| 100 | } |
||
| 101 | } |
||
| 102 | |||
| 103 | if($count > 5){ |
||
| 104 | $penalty += (3 + $count - 5); |
||
| 105 | } |
||
| 106 | |||
| 107 | } |
||
| 108 | } |
||
| 109 | |||
| 110 | return $penalty; |
||
| 111 | } |
||
| 112 | |||
| 113 | /** |
||
| 114 | * Checks for each 2x2 area of same-colored modules in the matrix |
||
| 115 | */ |
||
| 116 | private function testLevel2(array $m, int $size):int{ |
||
| 117 | $penalty = 0; |
||
| 118 | |||
| 119 | foreach($m as $y => $row){ |
||
| 120 | |||
| 121 | if($y > $size - 2){ |
||
| 122 | break; |
||
| 123 | } |
||
| 124 | |||
| 125 | foreach($row as $x => $val){ |
||
| 126 | |||
| 127 | if($x > $size - 2){ |
||
| 128 | break; |
||
| 129 | } |
||
| 130 | |||
| 131 | if( |
||
| 132 | $val === $m[$y][$x + 1] |
||
| 133 | && $val === $m[$y + 1][$x] |
||
| 134 | && $val === $m[$y + 1][$x + 1] |
||
| 135 | ){ |
||
| 136 | $penalty++; |
||
| 137 | } |
||
| 138 | } |
||
| 139 | } |
||
| 140 | |||
| 141 | return 3 * $penalty; |
||
| 142 | } |
||
| 143 | |||
| 144 | /** |
||
| 145 | * Checks if there are patterns that look similar to the finder patterns (1:1:3:1:1 ratio) |
||
| 146 | */ |
||
| 147 | private function testLevel3(array $m, int $size):int{ |
||
| 183 | } |
||
| 184 | |||
| 185 | /** |
||
| 186 | * Checks if more than half of the modules are dark or light, with a larger penalty for a larger difference |
||
| 187 | */ |
||
| 188 | private function testLevel4(array $m, int $size):float{ |
||
| 203 |