Completed
Branch transformers (91245b)
by Eugene
05:05
created

Packer::packInt()   D

Complexity

Conditions 10
Paths 10

Size

Total Lines 34
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 10

Importance

Changes 0
Metric Value
dl 0
loc 34
ccs 20
cts 20
cp 1
rs 4.8196
c 0
b 0
f 0
cc 10
eloc 20
nc 10
nop 1
crap 10

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\InvalidOptionException;
15
use MessagePack\Exception\PackingFailedException;
16
use MessagePack\TypeTransformer\Packable;
17
18
class Packer
19
{
20
    const UTF8_REGEX = '/\A(?:
21
          [\x00-\x7F]++                      # ASCII
22
        | [\xC2-\xDF][\x80-\xBF]             # non-overlong 2-byte
23
        |  \xE0[\xA0-\xBF][\x80-\xBF]        # excluding overlongs
24
        | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}  # straight 3-byte
25
        |  \xED[\x80-\x9F][\x80-\xBF]        # excluding surrogates
26
        |  \xF0[\x90-\xBF][\x80-\xBF]{2}     # planes 1-3
27
        | [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
28
        |  \xF4[\x80-\x8F][\x80-\xBF]{2}     # plane 16
29
        )*+\z/x';
30
31
    private $isDetectStrBin;
32
    private $isForceStr;
33
    private $isDetectArrMap;
34
    private $isForceArr;
35
    private $isForceFloat32;
36
37
    /**
38
     * @var Packable[]
39
     */
40
    private $transformers = [];
41
42
    /**
43
     * @param PackOptions|int|null $options
44
     *
45
     * @throws InvalidOptionException
46
     */
47 110
    public function __construct($options = null)
48
    {
49 110
        if (!$options instanceof PackOptions) {
50 110
            $options = PackOptions::fromBitmask($options);
51
        }
52
53 110
        $this->isDetectStrBin = $options->isDetectStrBinMode();
54 110
        $this->isForceStr = $options->isForceStrMode();
55 110
        $this->isDetectArrMap = $options->isDetectArrMapMode();
56 110
        $this->isForceArr = $options->isForceArrMode();
57 110
        $this->isForceFloat32 = $options->isForceFloat32Mode();
58 110
    }
59
60 2
    public function registerTransformer(Packable $transformer)
61
    {
62 2
        $this->transformers[] = $transformer;
63 2
    }
64
65 99
    public function pack($value)
66
    {
67 99
        if (\is_int($value)) {
68 52
            return $this->packInt($value);
69
        }
70 70
        if (\is_string($value)) {
71 33
            if ($this->isDetectStrBin) {
72 27
                return \preg_match(self::UTF8_REGEX, $value)
73 19
                    ? $this->packStr($value)
74 27
                    : $this->packBin($value);
75
            }
76
77 6
            return $this->isForceStr ? $this->packStr($value) : $this->packBin($value);
78
        }
79 47
        if (\is_array($value)) {
80 26
            if ($this->isDetectArrMap) {
81 19
                return \array_values($value) === $value
82 10
                    ? $this->packArray($value)
83 19
                    : $this->packMap($value);
84
            }
85
86 7
            return $this->isForceArr ? $this->packArray($value) : $this->packMap($value);
87
        }
88 25
        if (null === $value) {
89 3
            return $this->packNil();
90
        }
91 24
        if (\is_bool($value)) {
92 6
            return $this->packBool($value);
93
        }
94 19
        if (\is_float($value)) {
95 6
            return $this->isForceFloat32
96 1
                ? $this->packFloat32($value)
97 6
                : $this->packFloat64($value);
98
        }
99 13
        if ($value instanceof Ext) {
100 9
            return $this->packExt($value->type, $value->data);
101
        }
102 4
        if ($this->transformers) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->transformers of type MessagePack\TypeTransformer\Packable[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
103 2
            foreach ($this->transformers as $transformer) {
104 2
                if (null !== $packed = $transformer->pack($this, $value)) {
105 2
                    return $packed;
106
                }
107
            }
108
        }
109
110 3
        throw new PackingFailedException($value, 'Unsupported type.');
111
    }
112
113 13
    public function packArray(array $array)
114
    {
115 13
        $size = \count($array);
116
117 13 View Code Duplication
        if ($size <= 0xf) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
118 10
            $data = \chr(0x90 | $size);
119 3
        } elseif ($size <= 0xffff) {
120 2
            $data = "\xdc".\chr($size >> 8).\chr($size);
121
        } else {
122 1
            $data = \pack('CN', 0xdd, $size);
123
        }
124
125 13
        foreach ($array as $val) {
126 12
            $data .= $this->pack($val);
127
        }
128
129 13
        return $data;
130
    }
131
132 15
    public function packMap(array $map)
133
    {
134 15
        $size = \count($map);
135
136 15 View Code Duplication
        if ($size <= 0xf) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
137 12
            $data = \chr(0x80 | $size);
138 3
        } elseif ($size <= 0xffff) {
139 2
            $data = "\xde".\chr($size >> 8).\chr($size);
140
        } else {
141 1
            $data = \pack('CN', 0xdf, $size);
142
        }
143
144 15
        foreach ($map as $key => $val) {
145 15
            $data .= $this->pack($key);
146 15
            $data .= $this->pack($val);
147
        }
148
149 15
        return $data;
150
    }
151
152 22
    public function packStr($str)
153
    {
154 22
        $len = \strlen($str);
155
156 22
        if ($len < 32) {
157 15
            return \chr(0xa0 | $len).$str;
158
        }
159 7
        if ($len <= 0xff) {
160 4
            return "\xd9".\chr($len).$str;
161
        }
162 3
        if ($len <= 0xffff) {
163 2
            return "\xda".\chr($len >> 8).\chr($len).$str;
164
        }
165
166 1
        return \pack('CN', 0xdb, $len).$str;
167
    }
168
169 13
    public function packBin($str)
170
    {
171 13
        $len = \strlen($str);
172
173 13
        if ($len <= 0xff) {
174 11
            return "\xc4".\chr($len).$str;
175
        }
176 2
        if ($len <= 0xffff) {
177 1
            return "\xc5".\chr($len >> 8).\chr($len).$str;
178
        }
179
180 1
        return \pack('CN', 0xc6, $len).$str;
181
    }
182
183 9
    public function packExt($type, $data)
184
    {
185 9
        $len = \strlen($data);
186
187 9
        switch ($len) {
188 9
            case 1: return "\xd4".\chr($type).$data;
189 8
            case 2: return "\xd5".\chr($type).$data;
190 7
            case 4: return "\xd6".\chr($type).$data;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
191 6
            case 8: return "\xd7".\chr($type).$data;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
192 5
            case 16: return "\xd8".\chr($type).$data;
193
        }
194
195 4
        if ($len <= 0xff) {
196 2
            return "\xc7".\chr($len).\chr($type).$data;
197
        }
198 2
        if ($len <= 0xffff) {
199 1
            return \pack('CnC', 0xc8, $len, $type).$data;
200
        }
201
202 1
        return \pack('CNC', 0xc9, $len, $type).$data;
203
    }
204
205 3
    public function packNil()
206
    {
207 3
        return "\xc0";
208
    }
209
210 6
    public function packBool($val)
211
    {
212 6
        return $val ? "\xc3" : "\xc2";
213
    }
214
215 3
    public function packFloat32($num)
216
    {
217 3
        return "\xca".\strrev(\pack('f', $num));
218
    }
219
220 5
    public function packFloat64($num)
221
    {
222 5
        return "\xcb".\strrev(\pack('d', $num));
223
    }
224
225 52
    public function packInt($num)
226
    {
227 52
        if ($num >= 0) {
228 37
            if ($num <= 0x7f) {
229 25
                return \chr($num);
230
            }
231 16
            if ($num <= 0xff) {
232 6
                return "\xcc".\chr($num);
233
            }
234 12
            if ($num <= 0xffff) {
235 6
                return "\xcd".\chr($num >> 8).\chr($num);
236
            }
237 7
            if ($num <= 0xffffffff) {
238 5
                return \pack('CN', 0xce, $num);
239
            }
240
241 3
            return self::packUint64(0xcf, $num);
242
        }
243
244 16
        if ($num >= -0x20) {
245 4
            return \chr(0xe0 | $num);
246
        }
247 12
        if ($num >= -0x80) {
248 3
            return "\xd0".\chr($num);
249
        }
250 9
        if ($num >= -0x8000) {
251 3
            return "\xd1".\chr($num >> 8).\chr($num);
252
        }
253 6
        if ($num >= -0x80000000) {
254 3
            return \pack('CN', 0xd2, $num);
255
        }
256
257 3
        return self::packUint64(0xd3, $num);
258
    }
259
260 6
    private static function packUint64($code, $num)
261
    {
262 6
        $hi = ($num & 0xffffffff00000000) >> 32;
263 6
        $lo = $num & 0x00000000ffffffff;
264
265 6
        return \pack('CNN', $code, $hi, $lo);
266
    }
267
}
268