Passed
Push — master ( a996f8...998e87 )
by Wilmer
02:42
created

FlattenException::flattenArgs()   C

Complexity

Conditions 12
Paths 12

Size

Total Lines 34
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 13.152

Importance

Changes 0
Metric Value
cc 12
eloc 26
nc 12
nop 3
dl 0
loc 34
ccs 20
cts 25
cp 0.8
crap 13.152
rs 6.9666
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
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Debug;
6
7
/**
8
 * FlattenException wraps a PHP Exception to be able to serialize it.
9
 * Implements the Throwable interface
10
 * Basically, this class removes all objects from the trace.
11
 * Ported from Symfony components @link https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Debug/Exception/FlattenException.php
12
 */
13
class FlattenException
14
{
15
    /**
16
     * @var string
17
     */
18
    protected string $message;
19
    /**
20
     * @var mixed|int
21
     */
22
    protected $code;
23
    /**
24
     * @var string
25
     */
26
    protected string $file;
27
    /**
28
     * @var int
29
     */
30
    protected int $line;
31
32
    /**
33
     * @var FlattenException|null
34
     */
35
    private ?FlattenException $_previous;
36
    /**
37
     * @var array
38
     */
39
    private array $_trace;
40
    /**
41
     * @var string
42
     */
43
    private string $_toString;
44
    /**
45
     * @var string
46
     */
47
    private string $_class;
48
49
    /**
50
     * FlattenException constructor.
51
     * @param \Throwable $exception
52
     */
53 10
    public function __construct(\Throwable $exception)
54
    {
55 10
        $this->setMessage($exception->getMessage());
56 10
        $this->setCode($exception->getCode());
57 10
        $this->setFile($exception->getFile());
58 10
        $this->setLine($exception->getLine());
59 10
        $this->setTrace($exception->getTrace());
60 10
        $this->setToString($exception->__toString());
61 10
        $this->setClass(get_class($exception));
62
63 10
        $previous = $exception->getPrevious();
64 10
        if ($previous instanceof \Exception) {
65 1
            $this->setPrevious(new self($previous));
66
        }
67 10
    }
68
69
    /**
70
     * Gets the Exception message
71
     * @return string the Exception message as a string.
72
     */
73 1
    public function getMessage(): string
74
    {
75 1
        return $this->message;
76
    }
77
78
    /**
79
     * Gets the Exception code
80
     * @return mixed|int the exception code as integer.
81
     */
82 1
    public function getCode()
83
    {
84 1
        return $this->code;
85
    }
86
87
    /**
88
     * Gets the file in which the exception occurred
89
     * @return string the filename in which the exception was created.
90
     */
91 1
    public function getFile(): string
92
    {
93 1
        return $this->file;
94
    }
95
96
    /**
97
     * Gets the line in which the exception occurred
98
     * @return int the line number where the exception was created.
99
     */
100 1
    public function getLine(): int
101
    {
102 1
        return $this->line;
103
    }
104
105
    /**
106
     * Gets the stack trace
107
     * @return array the Exception stack trace as an array.
108
     */
109 2
    public function getTrace(): array
110
    {
111 2
        return $this->_trace;
112
    }
113
114
    /**
115
     * Returns previous Exception
116
     * @return FlattenException|null the previous `FlattenException` if available or null otherwise.
117
     */
118 1
    public function getPrevious(): ?FlattenException
119
    {
120 1
        return $this->_previous;
121
    }
122
123
    /**
124
     * Gets the stack trace as a string
125
     * @return string the Exception stack trace as a string.
126
     */
127 1
    public function getTraceAsString(): string
128
    {
129 1
        $remove = "Stack trace:\n";
130 1
        $len = strpos($this->_toString, $remove);
131 1
        if ($len === false) {
132
            return '';
133
        }
134 1
        return substr($this->_toString, $len + strlen($remove));
135
    }
136
137
    /**
138
     * String representation of the exception
139
     * @return string the string representation of the exception.
140
     */
141 1
    public function __toString()
142
    {
143 1
        return $this->_toString;
144
    }
145
146
    /**
147
     * @return string the name of the class in which the exception was created.
148
     */
149 1
    public function getClass(): string
150
    {
151 1
        return $this->_class;
152
    }
153
154
    /**
155
     * @param string $message the Exception message as a string.
156
     */
157 10
    protected function setMessage($message): void
158
    {
159 10
        $this->message = $message;
160 10
    }
161
162
    /**
163
     * @param mixed|int $code the exception code as integer.
164
     */
165 10
    protected function setCode($code): void
166
    {
167 10
        $this->code = $code;
168 10
    }
169
170
    /**
171
     * @param string $file the filename in which the exception was created.
172
     */
173 10
    protected function setFile($file): void
174
    {
175 10
        $this->file = $file;
176 10
    }
177
178
    /**
179
     * @param int $line the line number where the exception was created.
180
     */
181 10
    protected function setLine($line): void
182
    {
183 10
        $this->line = $line;
184 10
    }
185
186
    /**
187
     * @param array $trace the Exception stack trace as an array.
188
     */
189 10
    protected function setTrace($trace): void
190
    {
191 10
        $this->_trace = [];
192 10
        foreach ($trace as $entry) {
193 10
            $class = '';
194 10
            $namespace = '';
195 10
            if (isset($entry['class'])) {
196 10
                $parts = explode('\\', $entry['class']);
197 10
                $class = array_pop($parts);
198 10
                $namespace = implode('\\', $parts);
199
            }
200
201 10
            $this->_trace[] = [
202 10
                'namespace' => $namespace,
203 10
                'short_class' => $class,
204 10
                'class' => isset($entry['class']) ? $entry['class'] : '',
205 10
                'type' => isset($entry['type']) ? $entry['type'] : '',
206 10
                'function' => isset($entry['function']) ? $entry['function'] : null,
207 10
                'file' => isset($entry['file']) ? $entry['file'] : null,
208 10
                'line' => isset($entry['line']) ? $entry['line'] : null,
209 10
                'args' => isset($entry['args']) ? $this->flattenArgs($entry['args']) : [],
210
            ];
211
        }
212 10
    }
213
214
    /**
215
     * @param string $string the string representation of the thrown object.
216
     */
217 10
    protected function setToString($string): void
218
    {
219 10
        $this->_toString = $string;
220 10
    }
221
222
    /**
223
     * @param FlattenException $previous previous Exception.
224
     */
225 1
    protected function setPrevious(FlattenException $previous): void
226
    {
227 1
        $this->_previous = $previous;
228 1
    }
229
230
    /**
231
     * @param string $class the name of the class in which the exception was created.
232
     */
233 10
    protected function setClass($class): void
234
    {
235 10
        $this->_class = $class;
236 10
    }
237
238
    /**
239
     * Allows you to sterilize the Exception trace arguments
240
     * @param array $args
241
     * @param int $level recursion level
242
     * @param int $count number of records counter
243
     * @return array arguments tracing.
244
     */
245 10
    private function flattenArgs($args, $level = 0, &$count = 0): array
246
    {
247 10
        $result = [];
248 10
        foreach ($args as $key => $value) {
249 10
            if (++$count > 10000) {
250
                return ['array', '*SKIPPED over 10000 entries*'];
251
            }
252 10
            if ($value instanceof \__PHP_Incomplete_Class) {
253
                // is_object() returns false on PHP<=7.1
254
                $result[$key] = ['incomplete-object', $this->getClassNameFromIncomplete($value)];
255 10
            } elseif (is_object($value)) {
256 10
                $result[$key] = ['object', get_class($value)];
257 10
            } elseif (is_array($value)) {
258 10
                if ($level > 10) {
259
                    $result[$key] = ['array', '*DEEP NESTED ARRAY*'];
260
                } else {
261 10
                    $result[$key] = ['array', $this->flattenArgs($value, $level + 1, $count)];
262
                }
263 10
            } elseif (null === $value) {
264 10
                $result[$key] = ['null', null];
265 10
            } elseif (is_bool($value)) {
266 10
                $result[$key] = ['boolean', $value];
267 10
            } elseif (is_int($value)) {
268 10
                $result[$key] = ['integer', $value];
269 10
            } elseif (is_float($value)) {
270
                $result[$key] = ['float', $value];
271 10
            } elseif (is_resource($value)) {
272
                $result[$key] = ['resource', get_resource_type($value)];
273
            } else {
274 10
                $result[$key] = ['string', (string)$value];
275
            }
276
        }
277
278 10
        return $result;
279
    }
280
281
    /**
282
     * @param \__PHP_Incomplete_Class $value
283
     * @return string the real class name of an incomplete class
284
     */
285
    private function getClassNameFromIncomplete(\__PHP_Incomplete_Class $value): string
286
    {
287
        $array = new \ArrayObject($value);
288
289
        return $array['__PHP_Incomplete_Class_Name'];
290
    }
291
}
292