Completed
Push — develop ( 685e29...09d456 )
by Adrien
14:14
created

Functions::null()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 4
ccs 0
cts 0
cp 0
crap 2
rs 10
1
<?php
2
3
namespace PhpSpreadsheet\Calculation;
4
5
/* MAX_VALUE */
6 1
define('MAX_VALUE', 1.2e308);
7
8
/* 2 / PI */
9 1
define('M_2DIVPI', 0.63661977236758134307553505349006);
10
11
/* MAX_ITERATIONS */
12 1
define('MAX_ITERATIONS', 256);
13
14
/* PRECISION */
15 1
define('PRECISION', 8.88E-016);
16
17
/**
18
 * Copyright (c) 2006 - 2016 PhpSpreadsheet
19
 *
20
 * This library is free software; you can redistribute it and/or
21
 * modify it under the terms of the GNU Lesser General Public
22
 * License as published by the Free Software Foundation; either
23
 * version 2.1 of the License, or (at your option) any later version.
24
 *
25
 * This library is distributed in the hope that it will be useful,
26
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28
 * Lesser General Public License for more details.
29
 *
30
 * You should have received a copy of the GNU Lesser General Public
31
 * License along with this library; if not, write to the Free Software
32
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
33
 *
34
 * @category    PhpSpreadsheet
35
 * @copyright   Copyright (c) 2006 - 2016 PhpSpreadsheet (https://github.com/PHPOffice/PhpSpreadsheet)
36
 * @license     http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
37
 * @version     ##VERSION##, ##DATE##
38
 */
39
class Functions
40
{
41
    /** constants */
42
    const COMPATIBILITY_EXCEL = 'Excel';
43
    const COMPATIBILITY_GNUMERIC = 'Gnumeric';
44
    const COMPATIBILITY_OPENOFFICE = 'OpenOfficeCalc';
45
46
    const RETURNDATE_PHP_NUMERIC = 'P';
47
    const RETURNDATE_PHP_OBJECT = 'O';
48
    const RETURNDATE_EXCEL = 'E';
49
50
    /**
51
     * Compatibility mode to use for error checking and responses
52
     *
53
     * @var string
54
     */
55
    protected static $compatibilityMode = self::COMPATIBILITY_EXCEL;
56
57
    /**
58
     * Data Type to use when returning date values
59
     *
60
     * @var string
61
     */
62
    protected static $returnDateType = self::RETURNDATE_EXCEL;
63
64
    /**
65
     * List of error codes
66
     *
67
     * @var array
68
     */
69
    protected static $errorCodes = [
70
        'null' => '#NULL!',
71
        'divisionbyzero' => '#DIV/0!',
72
        'value' => '#VALUE!',
73
        'reference' => '#REF!',
74
        'name' => '#NAME?',
75
        'num' => '#NUM!',
76
        'na' => '#N/A',
77
        'gettingdata' => '#GETTING_DATA',
78
    ];
79
80
    /**
81
     * Set the Compatibility Mode
82
     *
83
     * @category Function Configuration
84
     * @param     string $compatibilityMode Compatibility Mode
85
     *                                                Permitted values are:
86
     *                                                    Functions::COMPATIBILITY_EXCEL            'Excel'
87
     *                                                    Functions::COMPATIBILITY_GNUMERIC        'Gnumeric'
88
     *                                                    Functions::COMPATIBILITY_OPENOFFICE    'OpenOfficeCalc'
89
     * @return     bool    (Success or Failure)
90
     */
91
    public static function setCompatibilityMode($compatibilityMode)
92
    {
93
        if (($compatibilityMode == self::COMPATIBILITY_EXCEL) ||
94
            ($compatibilityMode == self::COMPATIBILITY_GNUMERIC) ||
95
            ($compatibilityMode == self::COMPATIBILITY_OPENOFFICE)
96
        ) {
97
            self::$compatibilityMode = $compatibilityMode;
98 2974
99
            return true;
100 2974
        }
101 52
102 2974
        return false;
103
    }
104 2974
105 2974
    /**
106
     * Return the current Compatibility Mode
107
     *
108
     * @category Function Configuration
109
     * @return     string        Compatibility Mode
110
     *                            Possible Return values are:
111
     *                                Functions::COMPATIBILITY_EXCEL            'Excel'
112
     *                                Functions::COMPATIBILITY_GNUMERIC        'Gnumeric'
113
     *                                Functions::COMPATIBILITY_OPENOFFICE    'OpenOfficeCalc'
114
     */
115
    public static function getCompatibilityMode()
116
    {
117
        return self::$compatibilityMode;
118
    }
119
120
    /**
121
     * Set the Return Date Format used by functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object)
122 441
     *
123
     * @category Function Configuration
124 441
     * @param     string $returnDateType Return Date Format
125
     *                                                Permitted values are:
126
     *                                                    Functions::RETURNDATE_PHP_NUMERIC        'P'
127
     *                                                    Functions::RETURNDATE_PHP_OBJECT        'O'
128
     *                                                    Functions::RETURNDATE_EXCEL            'E'
129
     * @return     bool                            Success or failure
130
     */
131
    public static function setReturnDateType($returnDateType)
132
    {
133
        if (($returnDateType == self::RETURNDATE_PHP_NUMERIC) ||
134
            ($returnDateType == self::RETURNDATE_PHP_OBJECT) ||
135
            ($returnDateType == self::RETURNDATE_EXCEL)
136
        ) {
137
            self::$returnDateType = $returnDateType;
138
139
            return true;
140 165
        }
141
142 165
        return false;
143 165
    }
144 165
145
    /**
146 165
     * Return the current Return Date Format for functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object)
147 165
     *
148
     * @category Function Configuration
149
     * @return     string        Return Date Format
150
     *                            Possible Return values are:
151
     *                                Functions::RETURNDATE_PHP_NUMERIC        'P'
152
     *                                Functions::RETURNDATE_PHP_OBJECT        'O'
153
     *                                Functions::RETURNDATE_EXCEL            'E'
154
     */
155
    public static function getReturnDateType()
156
    {
157
        return self::$returnDateType;
158
    }
159
160
    /**
161
     * DUMMY
162
     *
163
     * @category Error Returns
164 328
     * @return    string    #Not Yet Implemented
165
     */
166 328
    public static function DUMMY()
167
    {
168
        return '#Not Yet Implemented';
169
    }
170
171
    /**
172
     * DIV0
173
     *
174
     * @category Error Returns
175
     * @return    string    #Not Yet Implemented
176
     */
177 1
    public static function DIV0()
178
    {
179 1
        return self::$errorCodes['divisionbyzero'];
180
    }
181
182
    /**
183
     * NA
184
     *
185
     * Excel Function:
186
     *        =NA()
187
     *
188
     * Returns the error value #N/A
189
     *        #N/A is the error value that means "no value is available."
190 10
     *
191
     * @category Logical Functions
192 10
     * @return    string    #N/A!
193
     */
194
    public static function NA()
195
    {
196
        return self::$errorCodes['na'];
197
    }
198
199
    /**
200
     * NaN
201
     *
202
     * Returns the error value #NUM!
203
     *
204
     * @category Error Returns
205
     * @return    string    #NUM!
206
     */
207
    public static function NAN()
208
    {
209 36
        return self::$errorCodes['num'];
210
    }
211 36
212
    /**
213
     * NAME
214
     *
215
     * Returns the error value #NAME?
216
     *
217
     * @category Error Returns
218
     * @return    string    #NAME?
219
     */
220
    public static function NAME()
221
    {
222
        return self::$errorCodes['name'];
223
    }
224 163
225
    /**
226 163
     * REF
227
     *
228
     * Returns the error value #REF!
229
     *
230
     * @category Error Returns
231
     * @return    string    #REF!
232
     */
233
    public static function REF()
234
    {
235
        return self::$errorCodes['reference'];
236
    }
237
238
    /**
239 5
     * NULL
240
     *
241 5
     * Returns the error value #NULL!
242
     *
243
     * @category Error Returns
244
     * @return    string    #NULL!
245
     */
246
    public static function null()
247
    {
248
        return self::$errorCodes['null'];
249
    }
250
251
    /**
252
     * VALUE
253
     *
254 1
     * Returns the error value #VALUE!
255
     *
256 1
     * @category Error Returns
257
     * @return    string    #VALUE!
258
     */
259
    public static function VALUE()
260
    {
261
        return self::$errorCodes['value'];
262
    }
263
264
    public static function isMatrixValue($idx)
265
    {
266
        return (substr_count($idx, '.') <= 1) || (preg_match('/\.[A-Z]/', $idx) > 0);
267
    }
268
269 1
    public static function isValue($idx)
270
    {
271 1
        return substr_count($idx, '.') == 0;
272
    }
273
274
    public static function isCellValue($idx)
275
    {
276
        return substr_count($idx, '.') > 1;
277
    }
278
279
    public static function ifCondition($condition)
280
    {
281
        $condition = self::flattenSingleValue($condition);
282
        if (!isset($condition{0})) {
283
            $condition = '=""';
284 167
        }
285
        if (!in_array($condition{0}, ['>', '<', '='])) {
286 167
            if (!is_numeric($condition)) {
287
                $condition = \PhpSpreadsheet\Calculation::wrapResult(strtoupper($condition));
288
            }
289
290 3
            return '=' . $condition;
291
        } else {
292 3
            preg_match('/([<>=]+)(.*)/', $condition, $matches);
293
            list(, $operator, $operand) = $matches;
294
295
            if (!is_numeric($operand)) {
296
                $operand = str_replace('"', '""', $operand);
297
                $operand = \PhpSpreadsheet\Calculation::wrapResult(strtoupper($operand));
298
            }
299
300
            return $operator . $operand;
301
        }
302 3
    }
303
304 3
    /**
305
     * ERROR_TYPE
306
     *
307
     * @param    mixed $value Value to check
308 5
     * @return    bool
309
     */
310 5
    public static function errorType($value = '')
311 5
    {
312
        $value = self::flattenSingleValue($value);
313
314 5
        $i = 1;
315
        foreach (self::$errorCodes as $errorCode) {
316
            if ($value === $errorCode) {
317
                return $i;
318
            }
319
            ++$i;
320 5
        }
321 5
322
        return self::NA();
323 5
    }
324 4
325 4
    /**
326
     * IS_BLANK
327
     *
328 5
     * @param    mixed $value Value to check
329
     * @return    bool
330
     */
331
    public static function isBlank($value = null)
332
    {
333
        if (!is_null($value)) {
334
            $value = self::flattenSingleValue($value);
335
        }
336
337
        return is_null($value);
338 14
    }
339
340 14
    /**
341
     * IS_ERR
342 14
     *
343 14
     * @param    mixed $value Value to check
344 14
     * @return    bool
345 7
     */
346
    public static function isErr($value = '')
347 13
    {
348
        $value = self::flattenSingleValue($value);
349 7
350
        return self::isError($value) && (!self::isNa(($value)));
351
    }
352
353
    /**
354
     * IS_ERROR
355
     *
356
     * @param    mixed $value Value to check
357
     * @return    bool
358
     */
359 16
    public static function isError($value = '')
360
    {
361 16
        $value = self::flattenSingleValue($value);
362 14
363
        if (!is_string($value)) {
364
            return false;
365 16
        }
366
367
        return in_array($value, array_values(self::$errorCodes));
368
    }
369
370
    /**
371
     * IS_NA
372
     *
373
     * @param    mixed $value Value to check
374
     * @return    bool
375 16
     */
376
    public static function isNa($value = '')
377 16
    {
378
        $value = self::flattenSingleValue($value);
379 16
380
        return $value === self::NA();
381
    }
382
383
    /**
384
     * IS_EVEN
385
     *
386
     * @param    mixed $value Value to check
387
     * @return    bool
388
     */
389 56 View Code Duplication
    public static function isEven($value = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
390
    {
391 56
        $value = self::flattenSingleValue($value);
392
393 56
        if ($value === null) {
394 16
            return self::NAME();
395
        } elseif ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) {
396 40
            return self::VALUE();
397
        }
398
399
        return $value % 2 == 0;
400
    }
401
402
    /**
403
     * IS_ODD
404
     *
405
     * @param    mixed $value Value to check
406 18
     * @return    bool
407
     */
408 18 View Code Duplication
    public static function isOdd($value = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
409
    {
410 18
        $value = self::flattenSingleValue($value);
411
412
        if ($value === null) {
413
            return self::NAME();
414
        } elseif ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) {
415
            return self::VALUE();
416
        }
417
418
        return abs($value) % 2 == 1;
419
    }
420 20
421
    /**
422 20
     * IS_NUMBER
423
     *
424 20
     * @param    mixed $value Value to check
425 2
     * @return    bool
426 18
     */
427 7
    public static function isNumber($value = null)
428
    {
429
        $value = self::flattenSingleValue($value);
430 11
431
        if (is_string($value)) {
432
            return false;
433
        }
434
435
        return is_numeric($value);
436
    }
437
438
    /**
439
     * IS_LOGICAL
440 20
     *
441
     * @param    mixed $value Value to check
442 20
     * @return    bool
443
     */
444 20
    public static function isLogical($value = null)
445 2
    {
446 18
        $value = self::flattenSingleValue($value);
447 7
448
        return is_bool($value);
449
    }
450 11
451
    /**
452
     * IS_TEXT
453
     *
454
     * @param    mixed $value Value to check
455
     * @return    bool
456
     */
457
    public static function isText($value = null)
458
    {
459
        $value = self::flattenSingleValue($value);
460 16
461
        return is_string($value) && !self::isError($value);
462 16
    }
463
464 16
    /**
465 8
     * IS_NONTEXT
466
     *
467 8
     * @param    mixed $value Value to check
468
     * @return    bool
469
     */
470
    public static function isNonText($value = null)
471
    {
472
        return !self::isText($value);
473
    }
474
475
    /**
476
     * VERSION
477 16
     *
478
     * @return    string    Version information
479 16
     */
480
    public static function VERSION()
481 16
    {
482
        return 'PhpSpreadsheet ##VERSION##, ##DATE##';
483
    }
484
485
    /**
486
     * N
487
     *
488
     * Returns a value converted to a number
489
     *
490
     * @param    value        The value you want converted
491 32
     * @return    number        N converts values listed in the following table
492
     *        If value is or refers to N returns
493 32
     *        A number            That number
494
     *        A date                The serial number of that date
495 32
     *        TRUE                1
496
     *        FALSE                0
497
     *        An error value        The error value
498
     *        Anything else        0
499
     */
500
    public static function n($value = null)
501
    {
502
        while (is_array($value)) {
503
            $value = array_shift($value);
504
        }
505 16
506
        switch (gettype($value)) {
507 16
            case 'double':
508
            case 'float':
509
            case 'integer':
510
                return $value;
511
            case 'boolean':
512
                return (integer) $value;
513
            case 'string':
514
                //    Errors
515
                if ((strlen($value) > 0) && ($value{0} == '#')) {
516
                    return $value;
517
                }
518
                break;
519
        }
520
521
        return 0;
522
    }
523
524
    /**
525
     * TYPE
526
     *
527
     * Returns a number that identifies the type of a value
528
     *
529
     * @param    value        The value you want tested
530
     * @return    number        N converts values listed in the following table
531
     *        If value is or refers to N returns
532
     *        A number            1
533
     *        Text                2
534
     *        Logical Value        4
535
     *        An error value        16
536
     *        Array or Matrix        64
537 20
     */
538
    public static function TYPE($value = null)
539 20
    {
540 9
        $value = self::flattenArrayIndexed($value);
0 ignored issues
show
Bug introduced by
It seems like $value can also be of type null; however, PhpSpreadsheet\Calculati...::flattenArrayIndexed() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
541
        if (is_array($value) && (count($value) > 1)) {
542
            end($value);
543 20
            $a = key($value);
544 20
            //    Range of cells is an error
545 19
            if (self::isCellValue($a)) {
546 19
                return 16;
547 8
                //    Test for Matrix
548 12
            } elseif (self::isMatrixValue($a)) {
549 1
                return 64;
550 11
            }
551
        } elseif (empty($value)) {
552 8
            //    Empty Cell
553 2
            return 1;
554
        }
555 6
        $value = self::flattenSingleValue($value);
556
557 9
        if (($value === null) || (is_float($value)) || (is_int($value))) {
558
            return 1;
559
        } elseif (is_bool($value)) {
560
            return 4;
561
        } elseif (is_array($value)) {
562
            return 64;
563
        } elseif (is_string($value)) {
564
            //    Errors
565
            if ((strlen($value) > 0) && ($value{0} == '#')) {
566
                return 16;
567
            }
568
569
            return 2;
570
        }
571
572
        return 0;
573
    }
574
575 16
    /**
576
     * Convert a multi-dimensional array to a simple 1-dimensional array
577 16
     *
578 16
     * @param    array $array Array to be flattened
579 3
     * @return    array    Flattened array
580 3
     */
581
    public static function flattenArray($array)
582 3
    {
583
        if (!is_array($array)) {
584
            return (array) $array;
585 3
        }
586 3
587
        $arrayValues = [];
588
        foreach ($array as $value) {
589
            if (is_array($value)) {
590 2
                foreach ($value as $val) {
591
                    if (is_array($val)) {
592 11
                        foreach ($val as $v) {
593
                            $arrayValues[] = $v;
594 11
                        }
595 4
                    } else {
596 7
                        $arrayValues[] = $val;
597 1
                    }
598 6
                }
599
            } else {
600 6
                $arrayValues[] = $value;
601
            }
602 6
        }
603 2
604
        return $arrayValues;
605 4
    }
606
607
    /**
608
     * Convert a multi-dimensional array to a simple 1-dimensional array, but retain an element of indexing
609
     *
610
     * @param    array $array Array to be flattened
611
     * @return    array    Flattened array
612
     */
613
    public static function flattenArrayIndexed($array)
614
    {
615
        if (!is_array($array)) {
616
            return (array) $array;
617 234
        }
618
619 234
        $arrayValues = [];
620
        foreach ($array as $k1 => $value) {
621
            if (is_array($value)) {
622
                foreach ($value as $k2 => $val) {
623 234
                    if (is_array($val)) {
624 234
                        foreach ($val as $k3 => $v) {
625 232
                            $arrayValues[$k1 . '.' . $k2 . '.' . $k3] = $v;
626 22
                        }
627 22
                    } else {
628 5
                        $arrayValues[$k1 . '.' . $k2] = $val;
629 5
                    }
630
                }
631
            } else {
632 22
                $arrayValues[$k1] = $value;
633
            }
634
        }
635
636 232
        return $arrayValues;
637
    }
638
639
    /**
640 234
     * Convert an array to a single scalar value by extracting the first element
641
     *
642
     * @param    mixed $value Array or scalar value
643
     * @return    mixed
644
     */
645
    public static function flattenSingleValue($value = '')
646
    {
647
        while (is_array($value)) {
648
            $value = array_pop($value);
649
        }
650 16
651
        return $value;
652 16
    }
653 11
}
654
655
//
656 5
//    There are a few mathematical functions that aren't available on all versions of PHP for all platforms
657 5
//    These functions aren't available in Windows implementations of PHP prior to version 5.3.0
658 5
//    So we test if they do exist for this version of PHP/operating platform; and if not we create them
659 2
//
660 2
if (!function_exists('acosh')) {
661
    function acosh($x)
662
    {
663
        return 2 * log(sqrt(($x + 1) / 2) + sqrt(($x - 1) / 2));
664
    }    //    function acosh()
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
665 2
}
666
667
if (!function_exists('asinh')) {
668
    function asinh($x)
669 5
    {
670
        return log($x + sqrt(1 + $x * $x));
671
    }    //    function asinh()
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
672
}
673 5
674
if (!function_exists('atanh')) {
675
    function atanh($x)
676
    {
677
        return (log(1 + $x) - log(1 - $x)) / 2;
678
    }    //    function atanh()
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
679
}
680
681
//
682
//    Strangely, PHP doesn't have a mb_str_replace multibyte function
683 2821
//    As we'll only ever use this function with UTF-8 characters, we can simply "hard-code" the character set
684
//
685 2821
if ((!function_exists('mb_str_replace')) &&
686 11
    (function_exists('mb_substr')) && (function_exists('mb_strlen')) && (function_exists('mb_strpos'))
687
) {
688
    function mb_str_replace($search, $replace, $subject)
689 2821
    {
690
        if (is_array($subject)) {
691
            $ret = [];
692
            foreach ($subject as $key => $val) {
693
                $ret[$key] = mb_str_replace($search, $replace, $val);
694
            }
695
696
            return $ret;
697
        }
698
699 1
        foreach ((array) $search as $key => $s) {
700
            if ($s == '' && $s !== 0) {
701
                continue;
702
            }
703
            $r = !is_array($replace) ? $replace : (array_key_exists($key, $replace) ? $replace[$key] : '');
704
            $pos = mb_strpos($subject, $s, 0, 'UTF-8');
705
            while ($pos !== false) {
706 1
                $subject = mb_substr($subject, 0, $pos, 'UTF-8') . $r . mb_substr($subject, $pos + mb_strlen($s, 'UTF-8'), 65535, 'UTF-8');
707
                $pos = mb_strpos($subject, $s, $pos + mb_strlen($r, 'UTF-8'), 'UTF-8');
708
            }
709
        }
710
711
        return $subject;
712
    }
713
}
714