Passed
Push — master ( 5545f1...83deac )
by Kirill
03:22
created

Serializer::serialize()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 7
rs 10
1
<?php
2
3
/**
4
 * Spiral Framework.
5
 *
6
 * @license   MIT
7
 * @author    Anton Titov (Wolfy-J)
8
 */
9
10
declare(strict_types=1);
11
12
namespace Spiral\Reactor;
13
14
use ReflectionClass;
15
use ReflectionException;
16
use Spiral\Reactor\Exception\SerializeException;
17
18
/**
19
 * Provides very simple api for serializing values. Attention, this is helper class, it's not
20
 * intended for processing user input.
21
 */
22
class Serializer
23
{
24
    /**
25
     * Fixed 4 spaces indent.
26
     */
27
    public const INDENT = DeclarationInterface::INDENT;
28
29
    /**
30
     * Serialize array.
31
     *
32
     * @param mixed $value
33
     * @return string
34
     * @throws ReflectionException
35
     */
36
    public function serialize($value): string
37
    {
38
        if (is_array($value)) {
39
            return $this->packArray($value);
40
        }
41
42
        return $this->packValue($value);
43
    }
44
45
    /**
46
     * @param array $array
47
     * @param int   $level
48
     * @return string
49
     * @throws ReflectionException
50
     */
51
    protected function packArray(array $array, int $level = 0): string
52
    {
53
        if ($array === []) {
54
            return '[]';
55
        }
56
        //Delimiters between rows and sub-arrays.
57
        $subIndent = "\n" . str_repeat(self::INDENT, $level + 2);
58
        $keyIndent = "\n" . str_repeat(self::INDENT, $level + 1);
59
        //No keys for associated array
60
        $associated = array_diff_key($array, array_keys(array_keys($array)));
61
        $result = [];
62
        $innerIndent = 0;
63
        if (!empty($associated)) {
64
            foreach ($array as $key => $value) {
65
                //Based on biggest key length
66
                $innerIndent = max(strlen(var_export($key, true)), $innerIndent);
67
            }
68
        }
69
        foreach ($array as $key => $value) {
70
            $prefix = '';
71
            if (!empty($associated)) {
72
                //Key prefix
73
                $prefix = str_pad(
74
                    var_export($key, true),
75
                    $innerIndent,
76
                    ' ',
77
                    STR_PAD_RIGHT
78
                ) . ' => ';
79
            }
80
            if (!is_array($value)) {
81
                $result[] = $prefix . $this->packValue($value);
82
                continue;
83
            }
84
            if ($value === []) {
85
                $result[] = $prefix . '[]';
86
                continue;
87
            }
88
            $subArray = $this->packArray($value, $level + 1);
89
            $result[] = $prefix . "[{$subIndent}" . $subArray . "{$keyIndent}]";
90
        }
91
        if ($level !== 0) {
92
            return $result ? implode(",{$keyIndent}", $result) : '';
93
        }
94
95
        return "[{$keyIndent}" . implode(",{$keyIndent}", $result) . "\n]";
96
    }
97
98
    /**
99
     * Pack array key value into string.
100
     *
101
     * @param mixed $value
102
     * @return string
103
     * @throws SerializeException
104
     * @throws ReflectionException
105
     */
106
    protected function packValue($value): string
107
    {
108
        if ($value instanceof DeclarationInterface) {
109
            //No indentation here
110
            return $value->render();
111
        }
112
113
        if ($value === null) {
114
            return 'null';
115
        }
116
117
        if (is_bool($value)) {
118
            return ($value ? 'true' : 'false');
119
        }
120
121
        if (is_object($value) && method_exists($value, '__set_state')) {
122
            return '\\' . var_export($value, true);
123
        }
124
125
        if (!is_string($value) && !is_numeric($value)) {
126
            throw new SerializeException('Unable to pack non scalar value');
127
        }
128
129
        if (is_string($value) && class_exists($value)) {
130
            $reflection = new ReflectionClass($value);
131
            if ($value === $reflection->getName()) {
132
                return '\\' . $reflection->getName() . '::class';
133
            }
134
        }
135
136
        return var_export($value, true);
137
    }
138
}
139