Completed
Push — master ( 528827...74b488 )
by Eugene
05:19 queued 11s
created

Packer   B

Complexity

Total Complexity 54

Size/Duplication

Total Lines 217
Duplicated Lines 11.06 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 100%

Importance

Changes 14
Bugs 1 Features 1
Metric Value
wmc 54
c 14
b 1
f 1
lcom 1
cbo 4
dl 24
loc 217
ccs 112
cts 112
cp 1
rs 7.0642

15 Methods

Rating   Name   Duplication   Size   Complexity  
A setTransformers() 0 4 1
A getTransformers() 0 4 1
C pack() 0 31 12
A packMap() 0 12 2
A packMapHeader() 11 11 3
A packStr() 0 16 4
A packBin() 0 13 3
C packExt() 0 23 8
A packNil() 0 4 1
A packBool() 0 4 2
A packDouble() 0 4 1
D packInt() 0 34 10
A packU64() 0 7 1
A packArray() 0 11 2
A packArrayHeader() 11 11 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

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:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Packer 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 Packer, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/*
4
 * This file is part of the rybakit/msgpack.php package.
5
 *
6
 * (c) Eugene Leonovich <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace MessagePack;
13
14
use MessagePack\Exception\PackingFailedException;
15
use MessagePack\TypeTransformer\Collection;
16
17
class Packer
18
{
19
    /**
20
     * @var Collection
21
     */
22
    private $transformers;
23
24
    /**
25
     * @param Collection|null $transformers
26
     */
27 2
    public function setTransformers(Collection $transformers = null)
28
    {
29 2
        $this->transformers = $transformers;
30 2
    }
31
32
    /**
33
     * @return Collection|null
34
     */
35 1
    public function getTransformers()
36
    {
37 1
        return $this->transformers;
38
    }
39
40 76
    public function pack($value)
41
    {
42 76
        $type = gettype($value);
43
44
        switch ($type) {
45 76
            case 'array':
46 13
                return array_values($value) === $value ? $this->packArray($value) : $this->packMap($value);
47 75
            case 'string':
48 23
                return preg_match('//u', $value) ? $this->packStr($value) : $this->packBin($value);
49 58
            case 'integer':
50 42
                return $this->packInt($value);
51 21
            case 'NULL':
52 3
                return $this->packNil();
53 20
            case 'boolean':
54 6
                return $this->packBool($value);
55 15
            case 'double':
56 3
                return $this->packDouble($value);
57
        }
58
59 12
        if ($value instanceof Ext) {
60 9
            return $this->packExt($value);
61
        }
62
63 3
        if ($this->transformers && $transformer = $this->transformers->match($value)) {
64 1
            $ext = new Ext($transformer->getId(), $this->pack($transformer->transform($value)));
65
66 1
            return $this->packExt($ext);
67
        }
68
69 2
        throw new PackingFailedException($value, 'Unsupported type.');
70
    }
71
72 7
    public function packArray(array $array)
73
    {
74 7
        $size = count($array);
75 7
        $data = self::packArrayHeader($size);
76
77 7
        foreach ($array as $val) {
78 6
            $data .= $this->pack($val);
79 7
        }
80
81 7
        return $data;
82
    }
83
84 7 View Code Duplication
    private static function packArrayHeader($size)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
85
    {
86 7
        if ($size <= 0xf) {
87 4
            return chr(0x90 | $size);
88
        }
89 3
        if ($size <= 0xffff) {
90 2
            return pack('Cn', 0xdc, $size);
91
        }
92
93 1
        return pack('CN', 0xdd, $size);
94
    }
95
96 8
    public function packMap(array $map)
97
    {
98 8
        $size = count($map);
99 8
        $data = self::packMapHeader($size);
100
101 8
        foreach ($map as $key => $val) {
102 8
            $data .= $this->pack($key);
103 8
            $data .= $this->pack($val);
104 8
        }
105
106 8
        return $data;
107
    }
108
109 8 View Code Duplication
    private static function packMapHeader($size)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
110
    {
111 8
        if ($size <= 0xf) {
112 5
            return chr(0x80 | $size);
113
        }
114 3
        if ($size <= 0xffff) {
115 2
            return pack('Cn', 0xde, $size);
116
        }
117
118 1
        return pack('CN', 0xdf, $size);
119
    }
120
121 17
    public function packStr($str)
122
    {
123 17
        $len = strlen($str);
124
125 17
        if ($len < 32) {
126 10
            return chr(0xa0 | $len).$str;
127
        }
128 7
        if ($len <= 0xff) {
129 4
            return pack('CC', 0xd9, $len).$str;
130
        }
131 3
        if ($len <= 0xffff) {
132 2
            return pack('Cn', 0xda, $len).$str;
133
        }
134
135 1
        return pack('CN', 0xdb, $len).$str;
136
    }
137
138 8
    public function packBin($str)
139
    {
140 8
        $len = strlen($str);
141
142 8
        if ($len <= 0xff) {
143 6
            return pack('CC', 0xc4, $len).$str;
144
        }
145 2
        if ($len <= 0xffff) {
146 1
            return pack('Cn', 0xc5, $len).$str;
147
        }
148
149 1
        return pack('CN', 0xc6, $len).$str;
150
    }
151
152 10
    public function packExt(Ext $ext)
153
    {
154 10
        $type = $ext->getType();
155 10
        $data = $ext->getData();
156 10
        $len = strlen($data);
157
158
        switch ($len) {
159 10
            case 1: return pack('CC', 0xd4, $type).$data;
160 8
            case 2: return pack('CC', 0xd5, $type).$data;
161 7
            case 4: return pack('CC', 0xd6, $type).$data;
162 6
            case 8: return pack('CC', 0xd7, $type).$data;
163 5
            case 16: return pack('CC', 0xd8, $type).$data;
164
        }
165
166 4
        if ($len <= 0xff) {
167 2
            return pack('CCC', 0xc7, $len, $type).$data;
168
        }
169 2
        if ($len <= 0xffff) {
170 1
            return pack('CnC', 0xc8, $len, $type).$data;
171
        }
172
173 1
        return pack('CNC', 0xc9, $len, $type).$data;
174
    }
175
176 3
    public function packNil()
177
    {
178 3
        return "\xc0";
179
    }
180
181 6
    public function packBool($val)
182
    {
183 6
        return $val ? "\xc3" : "\xc2";
184
    }
185
186 3
    public function packDouble($num)
187
    {
188 3
        return "\xcb".strrev(pack('d', $num));
189
    }
190
191 42
    public function packInt($num)
192
    {
193 42
        if ($num >= 0) {
194 27
            if ($num <= 0x7f) {
195 15
                return chr($num);
196
            }
197 16
            if ($num <= 0xff) {
198 6
                return pack('CC', 0xcc, $num);
199
            }
200 12
            if ($num <= 0xffff) {
201 6
                return pack('Cn', 0xcd, $num);
202
            }
203 7
            if ($num <= 0xffffffff) {
204 5
                return pack('CN', 0xce, $num);
205
            }
206
207 3
            return self::packU64(0xcf, $num);
208
        }
209
210 15
        if ($num >= -0x20) {
211 3
            return chr(0xe0 | $num);
212
        }
213 12
        if ($num >= -0x80) {
214 3
            return pack('CC', 0xd0, $num);
215
        }
216 9
        if ($num >= -0x8000) {
217 3
            return pack('Cn', 0xd1, $num);
218
        }
219 6
        if ($num >= -0x80000000) {
220 3
            return pack('CN', 0xd2, $num);
221
        }
222
223 3
        return self::packU64(0xd3, $num);
224
    }
225
226 6
    private static function packU64($code, $num)
227
    {
228 6
        $hi = ($num & 0xffffffff00000000) >> 32;
229 6
        $lo = $num & 0x00000000ffffffff;
230
231 6
        return pack('CNN', $code, $hi, $lo);
232
    }
233
}
234