Dumper::dumpAssociativeArray()   F
last analyzed

Complexity

Conditions 17
Paths 1032

Size

Total Lines 37
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 26
CRAP Score 17

Importance

Changes 0
Metric Value
cc 17
eloc 22
nc 1032
nop 2
dl 0
loc 37
ccs 26
cts 26
cp 1
crap 17
rs 1.0499
c 0
b 0
f 0

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
 * This file is part of NACL.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 *
8
 * @copyright 2019 Nuglif (2018) Inc.
9
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
10
 * @author    Pierrick Charron <[email protected]>
11
 * @author    Charle Demers <[email protected]>
12
 */
13
14
declare(strict_types=1);
15
16
namespace Nuglif\Nacl;
17
18
class Dumper
19
{
20
    public const PRETTY_PRINT               = 1 << 1;
21
    public const SEPARATOR_AFTER_NON_SCALAR = 1 << 2;
22
    public const SHORT_SINGLE_ELEMENT       = 1 << 3;
23
    public const NO_TRAILING_SEPARATOR      = 1 << 4;
24
    public const ROOT_BRACES                = 1 << 5;
25
    public const QUOTE_STR                  = 1 << 6;
26
27
    private string $indentStr = '  ';
28
29
    private string $assign = ' ';
30
31
    private string $separator = ';';
32
33
    private string $listSeparator = ',';
34
35
    private int $depth = 0;
36
37
    private int $options;
38
39 528
    public function __construct(int $options = 0)
40
    {
41 528
        $this->options = $options;
42
    }
43
44
    public function setIndent(string $str): void
45
    {
46
        $this->indentStr = $str;
47
    }
48
49
    public function setAssign(string $str): void
50
    {
51
        $this->assign = $str;
52
    }
53
54
    public function setSeparator(string $str): void
55
    {
56
        $this->separator = $str;
57
    }
58
59
    public function setListSeparator(string $str): void
60
    {
61
        $this->listSeparator = $str;
62
    }
63
64 528
    public function dump(mixed $var): string
65
    {
66 528
        return $this->dumpVar($var, !$this->hasOption(self::ROOT_BRACES));
67
    }
68
69 528
    private function dumpVar(mixed $var, bool $root = false): string
70
    {
71 528
        $varType = gettype($var);
72 528
        return match ($varType) {
73 528
            'array' => $this->dumpArray($var, $root),
74 528
            'string' => $this->dumpString($var),
75 528
            'integer', 'double', 'boolean' => var_export($var, true),
76 528
            'NULL' => 'null',
77 528
        };
78
    }
79
80 528
    private function dumpArray(array $var, bool $root = false): string
81
    {
82 528
        if ($this->isAssociativeArray($var)) {
83 462
            return $this->dumpAssociativeArray($var, $root);
84
        }
85
86 330
        return $this->dumpIndexedArray($var);
87
    }
88
89 462
    private function dumpAssociativeArray(array $var, bool $root = false): string
90
    {
91 462
        $inline = $this->hasOption(self::SHORT_SINGLE_ELEMENT) && (1 === count($var));
92 462
        $str    = '';
93
94 462
        if (!$root && !$inline) {
95 362
            $str .= '{' . $this->eol();
96 362
            ++$this->depth;
97
        }
98
99 462
        $remainingElements = count($var);
100
101 462
        foreach ($var as $key => $value) {
102 462
            --$remainingElements;
103
104 462
            $requireSep = !($this->hasOption(self::NO_TRAILING_SEPARATOR) && !$inline && !$remainingElements) && (
105 462
                !is_array($value) ||
106 462
                (
107 462
                    $this->hasOption(self::SEPARATOR_AFTER_NON_SCALAR) &&
108 462
                    (!$this->hasOption(self::SHORT_SINGLE_ELEMENT) || 1 !== count($value) || is_int(key($value)))
109 462
                )
110 462
            );
111
112 462
            $str .= ($inline ? '' : $this->indent())
113 462
                . $this->dumpString((string) $key)
114 462
                . $this->assign
115 462
                . $this->dumpVar($value)
116 462
                . ($requireSep ? $this->separator : '')
117 462
                . ($inline ? '' : $this->eol());
118
        }
119
120 462
        if (!$root && !$inline) {
121 362
            --$this->depth;
122 362
            $str .= $this->indent() . '}';
123
        }
124
125 462
        return $str;
126
    }
127
128 330
    private function dumpIndexedArray(array $var): string
129
    {
130 330
        $count = count($var);
131 330
        if (0 === $count) {
132
            return '[]';
133
        }
134
135 330
        $str = '[' . $this->eol();
136 330
        ++$this->depth;
137 330
        for ($i = 0; $i < $count; ++$i) {
138 330
            $str .= $this->indent() . rtrim($this->dumpVar($var[$i]), $this->separator);
139 330
            if ($count - 1 !== $i) {
140 330
                $str .= $this->listSeparator;
141
            }
142 330
            $str .= $this->eol();
143
        }
144 330
        --$this->depth;
145 330
        $str .= $this->indent() . ']';
146
147 330
        return $str;
148
    }
149
150 528
    private function dumpString(string $var): string
151
    {
152 528
        if (!$this->hasOption(self::QUOTE_STR) && preg_match('#^(' . Lexer::REGEX_NAME . ')$#A', $var)) {
153 448
            return match ($var) {
154 448
                'true', 'false', 'on', 'off', 'yes', 'no', 'null' => '"' . $var . '"',
155 448
                default => $var,
156 448
            };
157
        }
158
159 528
        return '"' . strtr($var, [
160 528
            "\b" => '\\b',
161 528
            "\f" => '\\f',
162 528
            "\r" => '\\r',
163 528
            "\n" => '\\n',
164 528
            "\t" => '\\t',
165 528
            '"'  => '\\"',
166 528
            '\\' => '\\\\',
167 528
        ]) . '"';
168
    }
169
170 528
    private function isAssociativeArray(array $var): bool
171
    {
172 528
        $i = 0;
173 528
        foreach (array_keys($var) as $key) {
174 528
            if ($key !== $i++) {
175 462
                return true;
176
            }
177
        }
178
179 330
        return false;
180
    }
181
182 464
    private function eol(): string
183
    {
184 464
        return $this->hasOption(self::PRETTY_PRINT) ? PHP_EOL : '';
185
    }
186
187 464
    private function indent(): string
188
    {
189 464
        return $this->hasOption(self::PRETTY_PRINT) ? str_repeat($this->indentStr, $this->depth) : '';
190
    }
191
192 528
    private function hasOption(int $opt): bool
193
    {
194 528
        return (bool) ($opt & $this->options);
195
    }
196
}
197