Passed
Push — developer ( 035509...e69f4b )
by Никита
03:03
created

Serializer::serialize_double()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 3
cts 3
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 1
crap 1
1
<?php
2
3
    namespace NokitaKaze\Serializer;
4
5
    class Serializer {
6
        const TYPE_INT = 0;
7
        const TYPE_DOUBLE = 1;
8
        const TYPE_STRING = 2;
9
        const TYPE_ARRAY_INDEX = 3;
10
        const TYPE_ARRAY_KEY_VALUE = 4;
11
        const TYPE_OBJECT_KEY_VALUE = 5;
12
        const TYPE_SERIALIZABLE = 6;
13
        const TYPE_RESOURCE = 7;
14
        const TYPE_BOOLEAN = 7;
15
        const TYPE_NULL = 8;
16
17
        const DEFAULT_DEPTH = 255;
18
19
        /**
20
         * @param mixed   $data
21
         * @param integer $depth
22
         *
23
         * @return string
24
         */
25 17
        public static function serialize($data, $depth = self::DEFAULT_DEPTH) {
26 17
            return json_encode(static::serialize_to_variant($data, $depth));
27
        }
28
29
        /**
30
         * @param mixed   $text
31
         * @param boolean $is_valid
32
         * @param boolean $safe
33
         *
34
         * @return mixed
35
         */
36 17
        public static function unserialize($text, &$is_valid, $safe = true) {
37 17
            $data = json_decode($text);
38
39
            // @todo text json
40
            try {
41 17
                $object = static::unserialize_variant_to_value($data, $safe);
42
            } catch (UnserializeException $e) {
43
                $is_valid = false;
44
45
                return null;
46
            }
47
48 17
            $is_valid = true;
49
50 17
            return $object;
51
        }
52
53
        /**
54
         * @param mixed   $data
55
         * @param integer $depth
56
         *
57
         * @return Variant|object|boolean|null
58
         */
59 17
        public static function serialize_to_variant($data, $depth = self::DEFAULT_DEPTH) {
60 17
            if ($depth < 0) {
61
                return null;
62
            }
63 17
            if (is_double($data)) {
64 8
                return static::serialize_double($data);
65 11
            } elseif (is_int($data)) {
66 4
                return static::serialize_int($data);
67 10
            } elseif (is_string($data)) {
68 5
                return static::serialize_string($data);
69 8
            } elseif (is_array($data) and static::is_indexed_array($data)) {
70 3
                return static::serialize_indexed_array($data);
71 7
            } elseif (is_array($data)) {
72 2
                return static::serialize_array_key_value($data);
73 6
            } elseif (is_object($data) and ($data instanceof ISerializable)) {
74
                return $data->serialize();
75 6
            } elseif (is_object($data)) {
76 2
                return static::serialize_object_key_value($data);
77 4
            } elseif (is_resource($data)) {
78
                // @todo
79
                return null;
80 4
            } elseif (is_bool($data)) {
81 3
                return $data;
82 2
            } elseif (is_null($data)) {
83 2
                return null;
84
            } else {
85
                return (object) [
86
                    'type' => self::TYPE_NULL,
87
                ];
88
            }
89
        }
90
91
        protected static $_binary_codes = [
92
            0, 1, 2, 3, 4, 5, 6, 7, 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 128, 129, 130,
93
            131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153,
94
            154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176,
95
            177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
96
            200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222,
97
            223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
98
            246, 247, 248, 249, 250, 251, 252, 253, 254,
99
        ];
100
101
        protected static $_binary_codes_flip = null;
102
103
        /**
104
         * @param string $value
105
         *
106
         * @return boolean
107
         */
108 17
        public static function is_binary_string($value) {
109 17
            if (is_null(self::$_binary_codes_flip)) {
110 1
                self::$_binary_codes_flip = array_flip(self::$_binary_codes);
111
            }
112
113
            // @todo Оптимизировать через > & <
114 17
            for ($i = 0; $i < strlen($value); $i++) {
115 17
                $ord = ord(substr($value, $i, 1));
116 17
                if (isset(self::$_binary_codes_flip[$ord])) {
117
                    return true;
118
                }
119
            }
120
121 17
            return false;
122
        }
123
124
        /**
125
         * @param double $value
126
         *
127
         * @return Variant|object
128
         */
129 8
        public static function serialize_double($value) {
130
            return (object) [
131 8
                'type' => self::TYPE_DOUBLE,
132 8
                'value' => serialize($value),
133
            ];
134
        }
135
136
        /**
137
         * @param integer $value
138
         *
139
         * @return Variant|object
140
         */
141 4
        public static function serialize_int($value) {
142
            return (object) [
143 4
                'type' => self::TYPE_INT,
144 4
                'value' => $value,
145
            ];
146
        }
147
148
        /**
149
         * @param array $value
150
         *
151
         * @return Variant|object
152
         */
153 3
        public static function serialize_indexed_array(array $value) {
154 3
            $output = [];
155 3
            foreach ($value as $sub_value) {
156 2
                $output[] = self::serialize_to_variant($sub_value);
157
            }
158
159
            return (object) [
160 3
                'type' => self::TYPE_ARRAY_INDEX,
161 3
                'value' => $output,
162
            ];
163
        }
164
165
        /**
166
         * @param array $value
167
         *
168
         * @return Variant|object
169
         */
170 2
        public static function serialize_array_key_value(array $value) {
171 2
            $output = [];
172 2
            $keys = [];
173 2
            foreach ($value as $key => $sub_value) {
174 2
                $keys[] = self::serialize_to_variant($key);
175 2
                $output[] = self::serialize_to_variant($sub_value);
176
            }
177
178
            return (object) [
179 2
                'type' => self::TYPE_ARRAY_KEY_VALUE,
180 2
                'value' => $output,
181 2
                'keys' => $keys,
182
            ];
183
        }
184
185
        /**
186
         * @param \stdClass|object $value
187
         *
188
         * @return Variant|object
189
         */
190 2
        public static function serialize_object_key_value(\stdClass $value) {
191 2
            $output = [];
192 2
            $keys = [];
193
194 2
            foreach (get_object_vars($value) as $key => $value) {
195 1
                $keys[] = self::serialize_to_variant($key);
196 1
                $output[] = self::serialize_to_variant($value);
197
            }
198
199
            return (object) [
200 2
                'type' => self::TYPE_OBJECT_KEY_VALUE,
201 2
                'value' => $output,
202 2
                'keys' => $keys,
203
            ];
204
        }
205
206
        /**
207
         * @param string $value
208
         *
209
         * @return Variant|object
210
         */
211 5
        public static function serialize_string($value) {
212
            return (object) [
213 5
                'type' => self::TYPE_STRING,
214 5
                'value' => base64_encode(gzcompress($value)),
215
            ];
216
        }
217
218
        /**
219
         * @param array $input
220
         *
221
         * @return boolean
222
         */
223 5
        public static function is_indexed_array(array $input) {
224 5
            if (empty($input)) {
225 1
                return true;
226
            }
227
228 4
            $keys = array_keys($input);
229 4
            for ($i = 0; $i < count($keys); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
230 4
                if ($keys[$i] !== $i) {
231 2
                    return false;
232
                }
233
            }
234
235 2
            return true;
236
        }
237
238
        /**
239
         * @param \stdClass|Variant $variant
240
         *
241
         * @return string
242
         */
243 5
        public static function unserialize_string(\stdClass $variant) {
244 5
            return gzuncompress(base64_decode($variant->value));
245
        }
246
247
        /**
248
         * @param \stdClass|Variant $variant
249
         * @param boolean           $safe
250
         *
251
         * @return array
252
         * @throws UnserializeException
253
         */
254 3
        public static function unserialize_array_index(\stdClass $variant, $safe) {
255 3
            $output = [];
256 3
            foreach ($variant->value as $sub_value) {
257 2
                $output[] = self::unserialize_variant_to_value($sub_value, $safe);
258
            }
259
260 3
            return $output;
261
        }
262
263
        /**
264
         * @param \stdClass|KeyValueVariant $variant
265
         * @param boolean                   $safe
266
         *
267
         * @return array
268
         * @throws UnserializeException
269
         */
270 4
        public static function unserialize_array_key_value(\stdClass $variant, $safe) {
271 4
            $count = count($variant->keys);
272 4
            if ($count != count($variant->value)) {
273
                throw new UnserializeException(sprintf('Array keys count (%d) does not equal value count (%d)',
274
                    $count,
275
                    count($variant->value)
276
                ), 2);
277
            }
278
279 4
            $output = [];
280 4
            for ($i = 0; $i < count($variant->keys); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
281 3
                $output[self::unserialize_variant_to_value($variant->keys[$i], $safe)]
282 3
                    = self::unserialize_variant_to_value($variant->value[$i], $safe);
283
            }
284
285 4
            return $output;
286
        }
287
288
        /**
289
         * @param Variant|boolean|null|object $variant
290
         * @param boolean                     $safe
291
         *
292
         * @return mixed
293
         * @throws UnserializeException
294
         */
295 17
        public static function unserialize_variant_to_value($variant, $safe) {
296 17
            if (is_null($variant)) {
297 2
                return null;
298 16
            } elseif (is_bool($variant)) {
299 3
                return $variant;
300
            } else {
301 16
                switch ($variant->type) {
302 16
                    case self::TYPE_INT:
303 4
                        return $variant->value;
304 15
                    case self::TYPE_DOUBLE:
305 8
                        return \unserialize($variant->value);
306 9
                    case self::TYPE_STRING:
307 5
                        return self::unserialize_string($variant);
308 7
                    case self::TYPE_ARRAY_INDEX:
309 3
                        return self::unserialize_array_index($variant, $safe);
310 4
                    case self::TYPE_ARRAY_KEY_VALUE:
311 2
                        return self::unserialize_array_key_value($variant, $safe);
312 2
                    case self::TYPE_OBJECT_KEY_VALUE:
313 2
                        return (object) self::unserialize_array_key_value($variant, $safe);
314
                    default:
315
                        throw new UnserializeException('Malformed type '.$variant->type, 1);
316
                }
317
            }
318
        }
319
320
    }
321
322
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...