|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
// Copyright (c) Lellys Informática. All rights reserved. See License.txt in the project root for license information. |
|
4
|
|
|
namespace Collections; |
|
5
|
|
|
|
|
6
|
|
|
use Collections\Iterator\VectorIterator; |
|
7
|
|
|
use Collections\Traits\GuardTrait; |
|
8
|
|
|
use Collections\Traits\StrictIterableTrait; |
|
9
|
|
|
use InvalidArgumentException; |
|
10
|
|
|
use Traversable; |
|
11
|
|
|
|
|
12
|
|
|
/** |
|
13
|
|
|
* Represents a strongly typed list of objects that can be accessed by index. Provides methods to search, sort, |
|
14
|
|
|
* and manipulate lists. |
|
15
|
|
|
*/ |
|
16
|
|
|
class ArrayList extends AbstractCollectionArray implements VectorInterface, \ArrayAccess |
|
17
|
|
|
{ |
|
18
|
|
|
use StrictIterableTrait, |
|
19
|
|
|
GuardTrait; |
|
20
|
|
|
|
|
21
|
1 |
|
public function at($key) |
|
22
|
|
|
{ |
|
23
|
1 |
|
$this->validateKeyType($key); |
|
24
|
1 |
|
$this->validateKeyBounds($key); |
|
25
|
|
|
|
|
26
|
1 |
|
return $this->container[$key]; |
|
27
|
|
|
} |
|
28
|
|
|
|
|
29
|
17 |
|
public function set($key, $value) |
|
30
|
|
|
{ |
|
31
|
17 |
|
$this->validateKeyType($key); |
|
32
|
16 |
|
$this->container[$key] = $value; |
|
33
|
|
|
|
|
34
|
16 |
|
return $this; |
|
35
|
|
|
} |
|
36
|
|
|
|
|
37
|
|
|
/** |
|
38
|
|
|
* {@inheritdoc} |
|
39
|
|
|
*/ |
|
40
|
1 |
|
public function get($index) |
|
41
|
|
|
{ |
|
42
|
1 |
|
$this->validateKeyType($index); |
|
43
|
|
|
|
|
44
|
1 |
|
return $this->container[$index]; |
|
45
|
|
|
} |
|
46
|
|
|
|
|
47
|
|
|
/** |
|
48
|
|
|
* {@inheritdoc} |
|
49
|
|
|
*/ |
|
50
|
22 |
|
public function add($item) |
|
51
|
|
|
{ |
|
52
|
22 |
|
$this->container[] = $item; |
|
53
|
|
|
|
|
54
|
22 |
|
return $this; |
|
55
|
|
|
} |
|
56
|
|
|
|
|
57
|
|
|
/** |
|
58
|
|
|
* {@inheritdoc} |
|
59
|
|
|
*/ |
|
60
|
3 |
|
public function addAll($items) |
|
61
|
|
|
{ |
|
62
|
3 |
|
if (!is_array($items) && !$items instanceof Traversable) { |
|
63
|
1 |
|
throw new \InvalidArgumentException('Parameter must be an array or an instance of Traversable'); |
|
64
|
|
|
} |
|
65
|
|
|
|
|
66
|
2 |
|
foreach ($items as $item) { |
|
67
|
2 |
|
if (is_array($item)) { |
|
68
|
|
|
$item = new static($item); |
|
69
|
|
|
} |
|
70
|
2 |
|
$this->add($item); |
|
71
|
2 |
|
} |
|
72
|
|
|
|
|
73
|
2 |
|
return $this; |
|
74
|
|
|
} |
|
75
|
|
|
|
|
76
|
|
|
/** |
|
77
|
|
|
* {@inheritdoc} |
|
78
|
|
|
*/ |
|
79
|
4 |
|
public function containsKey($key) |
|
80
|
|
|
{ |
|
81
|
4 |
|
$this->validateKeyType($key); |
|
82
|
|
|
|
|
83
|
3 |
|
return $key >= 0 && $key < $this->count(); |
|
84
|
|
|
} |
|
85
|
|
|
|
|
86
|
|
|
|
|
87
|
|
|
/** |
|
88
|
|
|
* {@inheritdoc} |
|
89
|
|
|
*/ |
|
90
|
3 |
|
public function removeKey($key) |
|
91
|
|
|
{ |
|
92
|
3 |
|
$this->validateKeyType($key); |
|
93
|
2 |
|
$this->validateKeyBounds($key); |
|
94
|
|
|
|
|
95
|
1 |
|
array_splice($this->container, $key, 1); |
|
96
|
|
|
|
|
97
|
1 |
|
return $this; |
|
98
|
|
|
} |
|
99
|
|
|
|
|
100
|
|
|
/** |
|
101
|
|
|
* {@inheritdoc} |
|
102
|
|
|
*/ |
|
103
|
3 |
|
public function indexOf($item) |
|
104
|
|
|
{ |
|
105
|
3 |
|
return array_search($item, $this->container, true); |
|
106
|
|
|
} |
|
107
|
|
|
|
|
108
|
|
|
/** |
|
109
|
|
|
* {@inheritdoc} |
|
110
|
|
|
*/ |
|
111
|
|
|
public function insert($index, $item) |
|
112
|
|
|
{ |
|
113
|
|
|
if (!is_numeric($index)) { |
|
114
|
|
|
throw new InvalidArgumentException('The index must be numeric'); |
|
115
|
|
|
} |
|
116
|
|
|
if ($index < 0 || $index >= $this->count()) { |
|
117
|
|
|
throw new InvalidArgumentException('The index is out of bounds (must be >=0 and <= size of te array)'); |
|
118
|
|
|
} |
|
119
|
|
|
|
|
120
|
|
|
$current = $this->count() - 1; |
|
121
|
|
|
for (; $current >= $index; $current--) { |
|
122
|
|
|
$this->container[$current + 1] = $this->container[$current]; |
|
123
|
|
|
} |
|
124
|
|
|
$this->container[$index] = $item; |
|
125
|
|
|
|
|
126
|
|
|
return $this; |
|
127
|
|
|
} |
|
128
|
|
|
|
|
129
|
|
|
/** |
|
130
|
|
|
* {@inheritdoc} |
|
131
|
|
|
*/ |
|
132
|
2 |
|
public function offsetExists($offset) |
|
133
|
|
|
{ |
|
134
|
2 |
|
$this->validateKeyType($offset); |
|
135
|
|
|
|
|
136
|
1 |
|
return $this->containsKey($offset) && $this->at($offset) !== null; |
|
137
|
|
|
} |
|
138
|
|
|
|
|
139
|
|
|
/** |
|
140
|
|
|
* {@inheritdoc} |
|
141
|
|
|
*/ |
|
142
|
1 |
|
public function offsetGet($offset) |
|
143
|
|
|
{ |
|
144
|
1 |
|
return $this->get($offset); |
|
145
|
|
|
} |
|
146
|
|
|
|
|
147
|
|
|
/** |
|
148
|
|
|
* {@inheritdoc} |
|
149
|
|
|
*/ |
|
150
|
19 |
|
public function offsetSet($offset, $value) |
|
151
|
|
|
{ |
|
152
|
19 |
|
if (is_null($offset)) { |
|
153
|
4 |
|
$this->add($value); |
|
154
|
4 |
|
} else { |
|
155
|
17 |
|
$this->set($offset, $value); |
|
156
|
|
|
} |
|
157
|
18 |
|
} |
|
158
|
|
|
|
|
159
|
|
|
/** |
|
160
|
|
|
* {@inheritdoc} |
|
161
|
|
|
*/ |
|
162
|
1 |
|
public function offsetUnset($offset) |
|
163
|
|
|
{ |
|
164
|
1 |
|
throw new \RuntimeException( |
|
165
|
1 |
|
'Cannot unset an element of a ' . get_class($this)); |
|
166
|
|
|
} |
|
167
|
|
|
|
|
168
|
|
|
/** |
|
169
|
|
|
* {@inheritdoc} |
|
170
|
|
|
*/ |
|
171
|
1 |
|
public function toMap() |
|
172
|
|
|
{ |
|
173
|
1 |
|
return new Dictionary($this->getIterator()); |
|
174
|
|
|
} |
|
175
|
|
|
|
|
176
|
|
|
/** |
|
177
|
|
|
* {@inheritdoc} |
|
178
|
|
|
*/ |
|
179
|
|
|
public function reverse() |
|
180
|
|
|
{ |
|
181
|
|
|
return static::fromArray(array_reverse($this->container)); |
|
182
|
|
|
} |
|
183
|
|
|
|
|
184
|
|
|
/** |
|
185
|
|
|
* {@inheritdoc} |
|
186
|
|
|
*/ |
|
187
|
|
|
public function splice($offset, $length = null) |
|
188
|
|
|
{ |
|
189
|
|
|
return static::fromArray(array_splice($this->container, $offset, $length)); |
|
190
|
|
|
} |
|
191
|
|
|
|
|
192
|
|
|
/** |
|
193
|
|
|
* {@inheritdoc} |
|
194
|
|
|
*/ |
|
195
|
|
|
public static function fromArray(array $arr) |
|
196
|
|
|
{ |
|
197
|
|
|
$map = new ArrayList(); |
|
198
|
|
|
foreach ($arr as $v) { |
|
199
|
|
|
if (is_array($v)) { |
|
200
|
|
|
$map->add(new ArrayList($v)); |
|
201
|
|
|
} else { |
|
202
|
|
|
$map->add($v); |
|
203
|
|
|
} |
|
204
|
|
|
} |
|
205
|
|
|
|
|
206
|
|
|
return $map; |
|
|
|
|
|
|
207
|
|
|
} |
|
208
|
|
|
|
|
209
|
|
|
/** |
|
210
|
|
|
* Gets the collection's iterator |
|
211
|
|
|
* @return VectorIterator |
|
212
|
|
|
*/ |
|
213
|
18 |
|
public function getIterator() |
|
214
|
|
|
{ |
|
215
|
18 |
|
return new VectorIterator($this->container); |
|
216
|
|
|
} |
|
217
|
|
|
} |
|
218
|
|
|
|
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_functionexpects aPostobject, and outputs the author of the post. The base classPostreturns a simple string and outputting a simple string will work just fine. However, the child classBlogPostwhich is a sub-type ofPostinstead decided to return anobject, and is therefore violating the SOLID principles. If aBlogPostwere passed tomy_function, PHP would not complain, but ultimately fail when executing thestrtouppercall in its body.