Completed
Pull Request — master (#32)
by kacper
07:23
created

BC   F

Complexity

Total Complexity 112

Size/Duplication

Total Lines 611
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 282
dl 0
loc 611
ccs 315
cts 315
cp 1
rs 2
c 0
b 0
f 0
wmc 112

43 Methods

Rating   Name   Duplication   Size   Complexity  
A floor() 0 12 4
A checkIsFloatCleanZeros() 0 3 1
A dechex() 0 10 2
A add() 0 10 2
A rand() 0 9 1
A comp() 0 13 2
A convertScientificNotationToString() 0 17 4
A sqrt() 0 9 2
A powMod() 0 20 5
A getDecimalsLengthFromNumber() 0 8 2
A exp() 0 9 2
A isNegative() 0 3 1
A checkNumber() 0 8 3
A powFractional() 0 18 1
A roundUp() 0 15 2
A getScale() 0 5 1
A log() 0 27 5
A trimTrailingZeroes() 0 7 3
A hexdec() 0 10 2
A roundDown() 0 15 2
A mod() 0 14 2
A mul() 0 10 2
A pow() 0 18 4
A fact() 0 17 4
A ceil() 0 12 4
A sub() 0 10 2
A div() 0 14 3
A round() 0 12 3
A checkIsFloat() 0 3 1
A max() 0 13 4
A min() 0 13 4
A bin2dec() 0 13 2
C bitOperatorHelper() 0 50 12
A alignBinLength() 0 3 1
A dec2bin() 0 16 3
A parseArgs() 0 7 2
A abs() 0 9 2
A decBaseHelper() 0 13 3
A setScale() 0 3 1
A bitXor() 0 3 1
A bitAnd() 0 6 1
A bitOr() 0 3 1
A recalculateNegative() 0 13 3

How to fix   Complexity   

Complex Class

Complex classes like BC often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use BC, and based on these observations, apply Extract Interface, too.

1
<?php
2
declare(strict_types=1);
3
4
namespace BCMathExtended;
5
6
use Closure;
7
use InvalidArgumentException;
8
use function dechex;
9
use function hexdec;
10
11
class BC
12
{
13
    public const COMPARE_EQUAL = 0;
14
    public const COMPARE_LEFT_GRATER = 1;
15
    public const COMPARE_RIGHT_GRATER = -1;
16
17
    protected const DEFAULT_SCALE = 100;
18
19
    protected const MAX_BASE = 256;
20
21
    protected const BIT_OPERATOR_AND = 'and';
22
    protected const BIT_OPERATOR_OR = 'or';
23
    protected const BIT_OPERATOR_XOR = 'xor';
24
25 47
    public static function round(string $number, int $precision = 0): string
26
    {
27 47
        $number = self::convertScientificNotationToString($number);
28 47
        if (self::checkIsFloat($number)) {
29 36
            if (self::isNegative($number)) {
30 4
                return self::sub($number, '0.' . str_repeat('0', $precision) . '5', $precision);
31
            }
32
33 32
            return self::add($number, '0.' . str_repeat('0', $precision) . '5', $precision);
34
        }
35
36 11
        return self::checkNumber($number);
37
    }
38
39 366
    public static function convertScientificNotationToString(string $number): string
40
    {
41
        // check if number is in scientific notation, first use stripos as is faster then preg_match
42 366
        if (false !== stripos($number, 'E') && preg_match('/(-?(\d+\.)?\d+)E([+-]?)(\d+)/i', $number, $regs)) {
43
            // calculate final scale of number
44 60
            $scale = $regs[4] + self::getDecimalsLengthFromNumber($regs[1]);
45 60
            $pow = self::pow('10', $regs[4], $scale);
46 60
            if ('-' === $regs[3]) {
47 25
                $number = self::div($regs[1], $pow, $scale);
48
            } else {
49 35
                $number = self::mul($pow, $regs[1], $scale);
50
            }
51
            // remove unnecessary 0 and dot from 0.000 is a 0
52 60
            $number = self::trimTrailingZeroes($number);
53
        }
54
55 366
        return self::checkNumber($number);
56
    }
57
58 92
    public static function getDecimalsLengthFromNumber(string $number): int
59
    {
60 92
        $check = explode('.', $number);
61 92
        if (!empty($check[1])) {
62 62
            return strlen($check[1]);
63
        }
64
65 30
        return 0;
66
    }
67
68 147
    public static function pow(string $leftOperand, string $rightOperand, ?int $scale = null): string
69
    {
70 147
        $leftOperand = self::convertScientificNotationToString($leftOperand);
71 147
        $rightOperand = self::convertScientificNotationToString($rightOperand);
72
73 147
        if (self::checkIsFloat($rightOperand)) {
74 7
            if (null === $scale) {
75 2
                return self::powFractional($leftOperand, $rightOperand);
76
            }
77
78 5
            return self::powFractional($leftOperand, $rightOperand, $scale);
79
        }
80
81 147
        if (null === $scale) {
82 74
            return bcpow($leftOperand, $rightOperand);
83
        }
84
85 76
        return bcpow($leftOperand, $rightOperand, $scale);
86
    }
87
88 263
    protected static function checkIsFloat(string $number): bool
89
    {
90 263
        return false !== strpos($number, '.');
91
    }
92
93 7
    protected static function powFractional(string $leftOperand, string $rightOperand, ?int $scale = null): string
94
    {
95
        // we need to increased scale to get correct results and avoid rounding error
96 7
        $increasedScale = $scale ?? self::getScale();
97 7
        $increasedScale *= 2;
98 7
        $decimals = explode('.', $rightOperand);
99
100 7
        return self::checkNumber(
101 7
            self::mul(
102 7
                self::exp(
103 7
                    self::mul(
104 7
                        self::log($leftOperand),
105 7
                        '0.' . $decimals[1],
106 7
                        $increasedScale
107
                    )
108
                ),
109 7
                self::pow($leftOperand, $decimals[0], $increasedScale),
110 7
                $scale
111
            )
112
        );
113
    }
114
115 40
    public static function getScale(): int
116
    {
117 40
        $sqrt = self::sqrt('2');
118
119 40
        return strlen(substr($sqrt, strpos($sqrt, '.') + 1));
120
    }
121
122 45
    public static function sqrt(string $operand, ?int $scale = null): string
123
    {
124 45
        $operand = self::convertScientificNotationToString($operand);
125
126 45
        if (null === $scale) {
127 41
            return bcsqrt($operand);
128
        }
129
130 5
        return bcsqrt($operand, $scale);
131
    }
132
133 366
    protected static function checkNumber(string $number): string
134
    {
135 366
        $number = str_replace('+', '', filter_var($number, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));
136 366
        if ('-0' === $number || !is_numeric($number)) {
137 27
            return '0';
138
        }
139
140 363
        return $number;
141
    }
142
143 167
    public static function mul(string $leftOperand, string $rightOperand, ?int $scale = null): string
144
    {
145 167
        $leftOperand = self::convertScientificNotationToString($leftOperand);
146 167
        $rightOperand = self::convertScientificNotationToString($rightOperand);
147
148 167
        if (null === $scale) {
149 60
            return bcmul($leftOperand, $rightOperand);
150
        }
151
152 109
        return bcmul($leftOperand, $rightOperand, $scale);
153
    }
154
155 15
    public static function exp(string $arg): string
156
    {
157 15
        $scale = self::DEFAULT_SCALE;
158 15
        $result = '1';
159 15
        for ($i = 299; $i > 0; $i--) {
160 15
            $result = self::add(self::mul(self::div($result, (string)$i, $scale), $arg, $scale), '1', $scale);
161
        }
162
163 15
        return $result;
164
    }
165
166 160
    public static function add(string $leftOperand, string $rightOperand, ?int $scale = null): string
167
    {
168 160
        $leftOperand = self::convertScientificNotationToString($leftOperand);
169 160
        $rightOperand = self::convertScientificNotationToString($rightOperand);
170
171 160
        if (null === $scale) {
172 41
            return bcadd($leftOperand, $rightOperand);
173
        }
174
175 122
        return bcadd($leftOperand, $rightOperand, $scale);
176
    }
177
178 131
    public static function div(string $leftOperand, string $rightOperand, ?int $scale = null): string
179
    {
180 131
        $leftOperand = self::convertScientificNotationToString($leftOperand);
181 131
        $rightOperand = self::convertScientificNotationToString($rightOperand);
182
183 131
        if ('0' === self::trimTrailingZeroes($rightOperand)) {
184 1
            throw new InvalidArgumentException('Division by zero');
185
        }
186
187 130
        if (null === $scale) {
188 45
            return bcdiv($leftOperand, $rightOperand);
189
        }
190
191 93
        return bcdiv($leftOperand, $rightOperand, $scale);
192
    }
193
194 12
    public static function log(string $arg): string
195
    {
196 12
        $arg = self::convertScientificNotationToString($arg);
197 12
        if ($arg === '0') {
198 1
            return '-INF';
199
        }
200 11
        if (self::COMPARE_RIGHT_GRATER === self::comp($arg, '0')) {
201 1
            return 'NAN';
202
        }
203 10
        $scale = self::DEFAULT_SCALE;
204 10
        $m = (string)log((float)$arg);
205 10
        $x = self::sub(self::div($arg, self::exp($m), $scale), '1', $scale);
206 10
        $res = '0';
207 10
        $pow = '1';
208 10
        $i = 1;
209
        do {
210 10
            $pow = self::mul($pow, $x, $scale);
211 10
            $sum = self::div($pow, (string)$i, $scale);
212 10
            if ($i % 2 === 1) {
213 10
                $res = self::add($res, $sum, $scale);
214
            } else {
215 9
                $res = self::sub($res, $sum, $scale);
216
            }
217 10
            $i++;
218 10
        } while (self::comp($sum, '0', $scale));
219
220 10
        return self::add($res, $m, $scale);
221
    }
222
223 64
    public static function comp(string $leftOperand, string $rightOperand, ?int $scale = null): int
224
    {
225 64
        $leftOperand = self::convertScientificNotationToString($leftOperand);
226 64
        $rightOperand = self::convertScientificNotationToString($rightOperand);
227
228 64
        if (null === $scale) {
229 53
            return bccomp($leftOperand, $rightOperand, max(strlen($leftOperand), strlen($rightOperand)));
230
        }
231
232 21
        return bccomp(
233 21
            $leftOperand,
234 21
            $rightOperand,
235 21
            $scale
236
        );
237
    }
238
239 78
    public static function sub(string $leftOperand, string $rightOperand, ?int $scale = null): string
240
    {
241 78
        $leftOperand = self::convertScientificNotationToString($leftOperand);
242 78
        $rightOperand = self::convertScientificNotationToString($rightOperand);
243
244 78
        if (null === $scale) {
245 47
            return bcsub($leftOperand, $rightOperand);
246
        }
247
248 33
        return bcsub($leftOperand, $rightOperand, $scale);
249
    }
250
251 185
    protected static function trimTrailingZeroes(string $number): string
252
    {
253 185
        if (false !== strpos($number, '.')) {
254 124
            $number = rtrim($number, '0');
255
        }
256
257 185
        return rtrim($number, '.') ?: '0';
258
    }
259
260 148
    protected static function isNegative(string $number): bool
261
    {
262 148
        return 0 === strncmp('-', $number, 1);
263
    }
264
265 2
    public static function rand(string $min, string $max): string
266
    {
267 2
        $max = self::convertScientificNotationToString($max);
268 2
        $min = self::convertScientificNotationToString($min);
269
270 2
        $difference = self::add(self::sub($max, $min), '1');
271 2
        $randPercent = self::div((string)mt_rand(), (string)mt_getrandmax(), 8);
272
273 2
        return self::add($min, self::mul($difference, $randPercent, 8), 0);
274
    }
275
276 1
    public static function max(...$ags): ?string
277
    {
278 1
        $max = null;
279 1
        foreach (self::parseArgs($ags) as $number) {
280 1
            $number = self::convertScientificNotationToString((string)$number);
281 1
            if (null === $max) {
282 1
                $max = $number;
283 1
            } elseif (self::comp((string)$max, $number) === self::COMPARE_RIGHT_GRATER) {
284 1
                $max = $number;
285
            }
286
        }
287
288 1
        return $max;
289
    }
290
291 1
    public static function min(...$ags): ?string
292
    {
293 1
        $min = null;
294 1
        foreach (self::parseArgs($ags) as $number) {
295 1
            $number = self::convertScientificNotationToString((string)$number);
296 1
            if (null === $min) {
297 1
                $min = $number;
298 1
            } elseif (self::comp((string)$min, $number) === self::COMPARE_LEFT_GRATER) {
299 1
                $min = $number;
300
            }
301
        }
302
303 1
        return $min;
304
    }
305
306 17
    public static function roundDown(string $number, int $precision = 0): string
307
    {
308 17
        $number = self::convertScientificNotationToString($number);
309 17
        $multiply = self::pow('10', (string)abs($precision));
310
311 17
        return $precision < 0
312
            ?
313 4
            self::mul(
314 4
                self::floor(self::div($number, $multiply, self::getDecimalsLengthFromNumber($number))), $multiply,
315 4
                $precision
316
            )
317
            :
318 13
            self::div(
319 13
                self::floor(self::mul($number, $multiply, self::getDecimalsLengthFromNumber($number))), $multiply,
320 17
                $precision
321
            );
322
    }
323
324 98
    public static function floor(string $number): string
325
    {
326 98
        $number = self::convertScientificNotationToString($number);
327 98
        if (self::checkIsFloat($number) && self::checkIsFloatCleanZeros($number)) {
328 38
            $result = 0;
329 38
            if (self::isNegative($number)) {
330 7
                --$result;
331
            }
332 38
            $number = self::add($number, (string)$result, 0);
333
        }
334
335 98
        return self::checkNumber($number);
336
    }
337
338 68
    protected static function checkIsFloatCleanZeros(string &$number): bool
339
    {
340 68
        return false !== strpos($number = self::trimTrailingZeroes($number), '.');
341
    }
342
343 17
    public static function roundUp(string $number, int $precision = 0): string
344
    {
345 17
        $number = self::convertScientificNotationToString($number);
346 17
        $multiply = self::pow('10', (string)abs($precision));
347
348 17
        return $precision < 0
349
            ?
350 4
            self::mul(
351 4
                self::ceil(self::div($number, $multiply, self::getDecimalsLengthFromNumber($number))), $multiply,
352 4
                $precision
353
            )
354
            :
355 13
            self::div(
356 13
                self::ceil(self::mul($number, $multiply, self::getDecimalsLengthFromNumber($number))), $multiply,
357 17
                $precision
358
            );
359
    }
360
361 41
    public static function ceil(string $number): string
362
    {
363 41
        $number = self::convertScientificNotationToString($number);
364 41
        if (self::checkIsFloat($number) && self::checkIsFloatCleanZeros($number)) {
365 22
            $result = 1;
366 22
            if (self::isNegative($number)) {
367 5
                --$result;
368
            }
369 22
            $number = self::add($number, (string)$result, 0);
370
        }
371
372 41
        return self::checkNumber($number);
373
    }
374
375 10
    public static function powMod(
376
        string $leftOperand,
377
        string $rightOperand,
378
        string $modulus,
379
        ?int $scale = null
380
    ): string {
381 10
        $leftOperand = self::convertScientificNotationToString($leftOperand);
382 10
        $rightOperand = self::convertScientificNotationToString($rightOperand);
383
384
        // bcpowmod in 5.6 have don't calculate correct results if scale is empty
385 10
        if (null === $scale) {
386 4
            return self::mod(self::pow($leftOperand, $rightOperand), $modulus);
387
        }
388
389
        // cant use bcpowmod here as it don't support floats
390 6
        if (self::checkIsFloat($leftOperand) || self::checkIsFloat($rightOperand) || self::checkIsFloat($modulus)) {
391 2
            return self::mod(self::pow($leftOperand, $rightOperand, $scale), $modulus, $scale);
392
        }
393
394 4
        return bcpowmod($leftOperand, $rightOperand, $modulus, $scale);
0 ignored issues
show
Bug Best Practice introduced by
The expression return bcpowmod($leftOpe...rand, $modulus, $scale) could return the type null which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
395
    }
396
397 56
    public static function mod(string $leftOperand, string $modulus, ?int $scale = null): string
398
    {
399 56
        $leftOperand = self::convertScientificNotationToString($leftOperand);
400
401
        // bcmod in 7.2 is not working properly - for example bcmod(9.9999E-10, -0.00056, 9) should return '-0.000559999' but returns 0.0000000
402
403
        // bcmod in php 5.6< don't support scale and floats
404
        // let use this $x - floor($x/$y) * $y;
405 56
        if (null === $scale) {
406 44
            return self::sub($leftOperand, self::mul(self::floor(self::div($leftOperand, $modulus)), $modulus));
407
        }
408
409 12
        return self::sub(
410 12
            $leftOperand, self::mul(self::floor(self::div($leftOperand, $modulus, $scale)), $modulus, $scale), $scale
411
        );
412
    }
413
414 8
    public static function fact(string $arg): string
415
    {
416 8
        $arg = self::convertScientificNotationToString($arg);
417
418 8
        if (self::checkIsFloat($arg)) {
419 1
            throw new InvalidArgumentException('Number has to be an integer');
420
        }
421 7
        if (self::isNegative($arg)) {
422 1
            throw new InvalidArgumentException('Number has to be greater than or equal to 0');
423
        }
424
425 6
        $return = '1';
426 6
        for ($i = 2; $i <= $arg; ++$i) {
427 5
            $return = self::mul($return, (string)$i);
428
        }
429
430 6
        return $return;
431
    }
432
433 5
    public static function hexdec(string $hex): string
434
    {
435 5
        $remainingDigits = substr($hex, 0, -1);
436 5
        $lastDigitToDecimal = (string)hexdec(substr($hex, -1));
437
438 5
        if ('' === $remainingDigits) {
439 5
            return $lastDigitToDecimal;
440
        }
441
442 5
        return self::add(self::mul('16', self::hexdec($remainingDigits)), $lastDigitToDecimal, 0);
443
    }
444
445 6
    public static function dechex(string $decimal): string
446
    {
447 6
        $quotient = self::div($decimal, '16', 0);
448 6
        $remainderToHex = dechex((int)self::mod($decimal, '16'));
449
450 6
        if (self::comp($quotient, '0') === self::COMPARE_EQUAL) {
451 6
            return $remainderToHex;
452
        }
453
454 6
        return self::dechex($quotient) . $remainderToHex;
455
    }
456
457 12
    public static function bitAnd
458
    (
459
        string $leftOperand,
460
        string $rightOperand
461
    ): string {
462 12
        return self::bitOperatorHelper($leftOperand, $rightOperand, self::BIT_OPERATOR_AND);
463
    }
464
465 36
    protected static function bitOperatorHelper(string $leftOperand, string $rightOperand, string $operator): string
466
    {
467 36
        $leftOperand = self::convertScientificNotationToString($leftOperand);
468 36
        $rightOperand = self::convertScientificNotationToString($rightOperand);
469
470 36
        if (self::checkIsFloat($leftOperand)) {
471 3
            throw new InvalidArgumentException('Left operator has to be an integer');
472
        }
473 33
        if (self::checkIsFloat($rightOperand)) {
474 3
            throw new InvalidArgumentException('Right operator has to be an integer');
475
        }
476
477 30
        $leftOperandNegative = self::isNegative($leftOperand);
478 30
        $rightOperandNegative = self::isNegative($rightOperand);
479
480 30
        $leftOperand = self::dec2bin(self::abs($leftOperand));
481 30
        $rightOperand = self::dec2bin(self::abs($rightOperand));
482
483 30
        $maxLength = max(strlen($leftOperand), strlen($rightOperand));
484
485 30
        $leftOperand = self::alignBinLength($leftOperand, $maxLength);
486 30
        $rightOperand = self::alignBinLength($rightOperand, $maxLength);
487
488 30
        if ($leftOperandNegative) {
489 7
            $leftOperand = self::recalculateNegative($leftOperand);
490
        }
491 30
        if ($rightOperandNegative) {
492 7
            $rightOperand = self::recalculateNegative($rightOperand);
493
        }
494
495 30
        $isNegative = false;
496 30
        $result = '';
497 30
        if (self::BIT_OPERATOR_AND === $operator) {
498 10
            $result = $leftOperand & $rightOperand;
499 10
            $isNegative = ($leftOperandNegative and $rightOperandNegative);
500 20
        } elseif (self::BIT_OPERATOR_OR === $operator) {
501 12
            $result = $leftOperand | $rightOperand;
502 12
            $isNegative = ($leftOperandNegative or $rightOperandNegative);
503 8
        } elseif (self::BIT_OPERATOR_XOR === $operator) {
504 8
            $result = $leftOperand ^ $rightOperand;
505 8
            $isNegative = ($leftOperandNegative xor $rightOperandNegative);
506
        }
507
508 30
        if ($isNegative) {
509 8
            $result = self::recalculateNegative($result);
510
        }
511
512 30
        $result = self::bin2dec($result);
513
514 30
        return $isNegative ? '-' . $result : $result;
515
    }
516
517 36
    public static function dec2bin(string $number, int $base = self::MAX_BASE): string
518
    {
519 36
        return self::decBaseHelper(
520
            $base, static function (int $base) use ($number) {
521 35
            $value = '';
522 35
            if ('0' === $number) {
523 30
                return chr((int)$number);
524
            }
525
526 33
            while (BC::comp($number, '0') !== BC::COMPARE_EQUAL) {
527 33
                $rest = BC::mod($number, (string)$base);
528 33
                $number = BC::div($number, (string)$base);
529 33
                $value = chr((int)$rest) . $value;
530
            }
531
532 33
            return $value;
533 36
        }
534
        );
535
    }
536
537 37
    protected static function decBaseHelper(int $base, Closure $closure): string
538
    {
539 37
        if ($base < 2 || $base > self::MAX_BASE) {
540 2
            throw new InvalidArgumentException('Invalid Base: ' . $base);
541
        }
542 35
        $orgScale = self::getScale();
543 35
        self::setScale(0);
544
545 35
        $value = $closure($base);
546
547 35
        self::setScale($orgScale);
548
549 35
        return $value;
550
    }
551
552 368
    public static function setScale(int $scale): void
553
    {
554 368
        bcscale($scale);
555 368
    }
556
557 45
    public static function abs(string $number): string
558
    {
559 45
        $number = self::convertScientificNotationToString($number);
560
561 45
        if (self::isNegative($number)) {
562 19
            $number = (string)substr($number, 1);
563
        }
564
565 45
        return self::checkNumber($number);
566
    }
567
568 30
    protected static function alignBinLength(string $string, int $length): string
569
    {
570 30
        return str_pad($string, $length, self::dec2bin('0'), STR_PAD_LEFT);
571
    }
572
573 11
    protected static function recalculateNegative(string $number): string
574
    {
575 11
        $xor = str_repeat(self::dec2bin((string)(self::MAX_BASE - 1)), strlen($number));
576 11
        $number ^= $xor;
577 11
        for ($i = strlen($number) - 1; $i >= 0; $i--) {
578 11
            $byte = ord($number[$i]);
579 11
            if (++$byte !== self::MAX_BASE) {
580 11
                $number[$i] = chr($byte);
581 11
                break;
582
            }
583
        }
584
585 11
        return $number;
586
    }
587
588 36
    public static function bin2dec(string $binary, int $base = self::MAX_BASE): string
589
    {
590 36
        return self::decBaseHelper(
591
            $base, static function (int $base) use ($binary) {
592 35
            $size = strlen($binary);
593 35
            $return = '0';
594 35
            for ($i = 0; $i < $size; ++$i) {
595 35
                $element = ord($binary[$i]);
596 35
                $power = BC::pow((string)$base, (string)($size - $i - 1));
597 35
                $return = BC::add($return, BC::mul((string)$element, $power));
598
            }
599
600 35
            return $return;
601 36
        }
602
        );
603
    }
604
605 14
    public static function bitOr(string $leftOperand, string $rightOperand): string
606
    {
607 14
        return self::bitOperatorHelper($leftOperand, $rightOperand, self::BIT_OPERATOR_OR);
608
    }
609
610 10
    public static function bitXor(string $leftOperand, string $rightOperand): string
611
    {
612 10
        return self::bitOperatorHelper($leftOperand, $rightOperand, self::BIT_OPERATOR_XOR);
613
    }
614
615 2
    protected static function parseArgs(array $args): array
616
    {
617 2
        if (is_array($args[0])) {
618 2
            $args = $args[0];
619
        }
620
621 2
        return $args;
622
    }
623
}
624