Passed
Push — master ( c0c747...ed64b8 )
by Adrian Florin
02:01
created

ArrayHelper::getValueFromDepth()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 5
ccs 3
cts 3
cp 1
rs 9.4285
cc 1
eloc 3
nc 1
nop 2
crap 1
1
<?php
2
/**
3
 * This file is part of the NeedleProject\Common package.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
namespace NeedleProject\Common\Helper;
9
10
use NeedleProject\Common\Exception\NotFoundException;
11
12
/**
13
 * Class ErrorToExceptionConverter
14
 *
15
 * @package NeedleProject\Common\Helper
16
 * @author Adrian Tilita <[email protected]>
17
 * @copyright 2017 Adrian Tilita
18
 * @license https://opensource.org/licenses/MIT MIT Licence
19
 */
20
class ArrayHelper
21
{
22
    const USAGE_EXISTS = 'hasKey';
23
    const USAGE_EXTRACT = 'getValue';
24
25
    /**
26
     * Verify if a key exist in depth
27
     *
28
     * @param array $haystack  - The array in which to search
29
     * @param array $keys - an array with the linear items treated as depth.
30
     *                      Ex: array('first_level','second_level','third_level')
31
     * @return bool
32
     * @throws \NeedleProject\Common\Exception\NotFoundException
33
     */
34 11
    public function hasKeysInDepth($haystack, $keys)
35
    {
36 11
        $this->validateInput($haystack, $keys);
37 4
        return $this->getNode($haystack, $keys, static::USAGE_EXISTS);
38
    }
39
40
    /**
41
     * Get a value in depth of an array
42
     *
43
     * @param array $haystack - The array in which to search
44
     * @param array $keys     - an array with the linear items treated as depth.
45
     *                          Ex: array('first_level','second_level','third_level')
46
     * @return mixed
47
     * @throws \NeedleProject\Common\Exception\NotFoundException
48
     */
49 10
    public function getValueFromDepth($haystack, $keys)
50
    {
51 10
        $this->validateInput($haystack, $keys);
52 3
        return $this->getNode($haystack, $keys, static::USAGE_EXTRACT);
53
    }
54
55
    /**
56
     * @param array  $haystack
57
     * @param array  $keys
58
     * @param string $searchType    Added search type to reuse the same code
59
     *                              even if it increases the complexity (for ~20 line)
60
     * @throws \NeedleProject\Common\Exception\NotFoundException
61
     * @return mixed
62
     */
63 7
    private function getNode($haystack, $keys, $searchType)
64
    {
65 7
        $depth = count($keys);
66 7
        for ($i = 0; $i < $depth; $i++) {
67 7
            $needle = $keys[$i];
68 7
            $isLast = ($i + 1) === $depth;
69 7
            if ($isLast && array_key_exists($needle, $haystack)) {
70 4
                $node = $haystack[$needle];
71 4
                break;
72
            }
73 7
            if ($isLast || !isset($haystack[$needle]) || !is_array($haystack[$needle])) {
74 3
                if (static::USAGE_EXISTS === $searchType) {
75 2
                    return false;
76
                }
77 1
                throw new NotFoundException("Given path does not exists.");
78
            }
79 6
            $haystack = $haystack[$needle];
80
        }
81 4
        return (static::USAGE_EXISTS === $searchType) ? true : $node;
0 ignored issues
show
Bug introduced by
The variable $node does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
82
    }
83
84
    /**
85
     * Validate if the given input are valid array
86
     * @param array $haystack
87
     * @param array $keys
88
     */
89 21
    private function validateInput($haystack, $keys)
90
    {
91 21
        if (!is_array($haystack) || empty($haystack)) {
92 12
            throw new \InvalidArgumentException(
93 12
                "Provided input array is either empty or not an array."
94
            );
95
        }
96 9
        if (!is_array($keys) || empty($keys)) {
97 2
            throw new \InvalidArgumentException(
98 2
                "Provided input keys argument is either empty or not an array."
99
            );
100
        }
101 7
    }
102
}
103