Completed
Push — master ( 9200c2...dc0c42 )
by Carlos C
7s
created

AbstractMap::removeExact()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 13
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 13
rs 9.4285
cc 3
eloc 10
nc 4
nop 2
1
<?php namespace GenericCollections\Abstracts;
2
3
use GenericCollections\Collection;
4
use GenericCollections\Interfaces\MapInterface;
5
use GenericCollections\Set;
6
use GenericCollections\Utils\TypeChecker;
7
8
abstract class AbstractMap extends InternalDataArray implements MapInterface, \ArrayAccess
9
{
10
    public function checkValueType($value)
11
    {
12
        return TypeChecker::getInstance()->checkType($this->getValueType(), $value);
13
    }
14
15
    public function checkKeyType($key)
16
    {
17
        return TypeChecker::getInstance()->checkType($this->getKeyType(), $key);
18
    }
19
20
    public function containsKey($key)
21
    {
22
        return $this->checkKeyType($key) and array_key_exists($key, $this->data);
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
23
    }
24
25
    public function containsValue($value)
26
    {
27
        return in_array($value, $this->data, $this->isComparisonIdentical());
28
    }
29
30
    public function get($key)
31
    {
32
        return $this->containsKey($key) ? $this->data[$key] : null;
33
    }
34
35
    public function getOrDefault($key, $default)
36
    {
37
        if ($this->containsKey($key)) {
38
            return $this->data[$key];
39
        }
40
        if (null !== $default and ! $this->checkValueType($default)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
41
            throw new \InvalidArgumentException(
42
                'The default value provided for '
43
                . get_class($this) . '::getOrDefault is not a valid type,'
44
                . ' expected ' . $this->getKeyType() . '.'
45
            );
46
        }
47
        return $default;
48
    }
49
50
    public function keys()
51
    {
52
        return array_keys($this->data);
53
    }
54
55
    public function put($key, $value)
56
    {
57 View Code Duplication
        if (! $this->checkKeyType($key)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
58
            throw new \InvalidArgumentException(
59
                'The key provided for ' . get_class($this)
60
                . '::put is not a valid type,'
61
                . ' expected ' . $this->getKeyType() . '.'
62
            );
63
        }
64 View Code Duplication
        if (! $this->checkValueType($value)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
65
            throw new \InvalidArgumentException(
66
                'The value provided for ' . get_class($this)
67
                . '::put is not a valid type,'
68
                . ' expected ' . $this->getValueType() . '.'
69
            );
70
        }
71
        $previous = $this->get($key);
72
        $this->data[$key] = $value;
73
        return $previous;
74
    }
75
76
    public function putAll(array $values)
77
    {
78
        foreach ($values as $key => $value) {
79
            $this->put($key, $value);
80
        }
81
    }
82
83
    public function putIfAbsent($key, $value)
84
    {
85
        $current = $this->get($key);
86
        if (null !== $current) {
87
            return $current;
88
        }
89
        $this->put($key, $value);
90
        return null;
91
    }
92
93
    public function remove($key)
94
    {
95
        $previous = $this->get($key);
96
        if ($previous !== null) {
97
            unset($this->data[$key]);
98
        }
99
        return $previous;
100
    }
101
102
    public function removeExact($key, $value)
103
    {
104
        $changed = false;
105
        $previous = $this->get($key);
106
        $isequal = ($this->isComparisonIdentical())
107
            ? ($previous === $value)
108
            : ($previous == $value);
109
        if ($isequal) {
110
            unset($this->data[$key]);
111
            $changed = true;
112
        }
113
        return $changed;
114
    }
115
116
    public function replace($key, $value)
117
    {
118
        return ($this->containsKey($key)) ? $this->put($key, $value) : null;
119
    }
120
121
    public function replaceExact($key, $current, $replacement)
122
    {
123
        if (! $this->containsKey($key)) {
124
            return false;
125
        }
126
        $previous = $this->get($key);
127
        $isequal = ($this->isComparisonIdentical())
128
            ? ($previous === $current)
129
            : ($previous == $current);
130
        if ($isequal) {
131
            $this->put($key, $replacement);
132
            return true;
133
        }
134
        return false;
135
    }
136
137
    public function keysSet()
138
    {
139
        return new Set($this->getKeyType(), $this->keys());
140
    }
141
142
    public function valuesCollection()
143
    {
144
        return new Collection($this->getValueType(), $this->toArray());
145
    }
146
147
148
149
    /*
150
     * Implementations from \ArrayAccess
151
     */
152
    /** @inheritdoc */
153
    public function offsetExists($offset)
154
    {
155
        return $this->containsKey($offset);
156
    }
157
158
    /** @inheritdoc */
159
    public function offsetGet($offset)
160
    {
161
        return $this->get($offset);
162
    }
163
164
    /** @inheritdoc */
165
    public function offsetSet($offset, $value)
166
    {
167
        $this->put($offset, $value);
168
    }
169
170
    /** @inheritdoc */
171
    public function offsetUnset($offset)
172
    {
173
        $this->remove($offset);
174
    }
175
}
176