Skip to content

Commit 8d7e501

Browse files
authored
Merge pull request #14 from boesing/feature/immutability
2 parents 38ab698 + 6b5efa1 commit 8d7e501

File tree

8 files changed

+89
-78
lines changed

8 files changed

+89
-78
lines changed

src/ArrayInterface.php

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,37 +14,31 @@
1414
* @template TKey of array-key
1515
* @template TValue
1616
* @template-extends IteratorAggregate<TKey,TValue>
17+
* @psalm-immutable
1718
*/
1819
interface ArrayInterface extends IteratorAggregate, Countable
1920
{
2021
/**
2122
* @psalm-param TValue $element
22-
* @psalm-mutation-free
2323
*/
2424
public function contains($element): bool;
2525

2626
/**
2727
* @psalm-return TValue
28-
* @psalm-mutation-free
2928
* @throws OutOfBoundsException if there are no values available.
3029
*/
3130
public function first();
3231

3332
/**
3433
* @psalm-return TValue
35-
* @psalm-mutation-free
3634
* @throws OutOfBoundsException if there are no values available.
3735
*/
3836
public function last();
3937

40-
/**
41-
* @psalm-mutation-free
42-
*/
4338
public function isEmpty(): bool;
4439

4540
/**
4641
* @psalm-return array<TKey,TValue>
47-
* @psalm-mutation-free
4842
*/
4943
public function toNativeArray(): array;
5044
}

src/Array_.php

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
* @template TKey of array-key
2323
* @template TValue
2424
* @template-implements ArrayInterface<TKey,TValue>
25+
* @psalm-immutable
2526
*/
2627
abstract class Array_ implements ArrayInterface
2728
{
@@ -31,7 +32,7 @@ abstract class Array_ implements ArrayInterface
3132
/**
3233
* @psalm-param array<TKey,TValue> $data
3334
*/
34-
public function __construct(array $data)
35+
protected function __construct(array $data)
3536
{
3637
$this->data = $data;
3738
}
@@ -44,17 +45,11 @@ public function getIterator(): Traversable
4445
return new ArrayIterator($this->data);
4546
}
4647

47-
/**
48-
* @psalm-mutation-free
49-
*/
5048
public function contains($element): bool
5149
{
5250
return in_array($element, $this->data, true);
5351
}
5452

55-
/**
56-
* @psalm-mutation-free
57-
*/
5853
public function first()
5954
{
6055
if ($this->isEmpty()) {
@@ -64,9 +59,6 @@ public function first()
6459
return reset($this->data);
6560
}
6661

67-
/**
68-
* @psalm-mutation-free
69-
*/
7062
public function last()
7163
{
7264
if ($this->isEmpty()) {
@@ -76,25 +68,16 @@ public function last()
7668
return end($this->data);
7769
}
7870

79-
/**
80-
* @psalm-mutation-free
81-
*/
8271
public function isEmpty(): bool
8372
{
8473
return $this->count() === 0;
8574
}
8675

87-
/**
88-
* @psalm-mutation-free
89-
*/
9076
public function count(): int
9177
{
9278
return count($this->data);
9379
}
9480

95-
/**
96-
* @psalm-mutation-free
97-
*/
9881
public function toNativeArray(): array
9982
{
10083
return $this->data;

src/GenericMap.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
* @template TKey of string
99
* @template TValue
1010
* @template-extends Map<TKey,TValue>
11+
* @psalm-immutable
1112
*/
1213
final class GenericMap extends Map
1314
{

src/GenericOrderedList.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
/**
88
* @template TValue
99
* @template-extends OrderedList<TValue>
10+
* @psalm-immutable
1011
*/
1112
final class GenericOrderedList extends OrderedList
1213
{

src/Map.php

Lines changed: 53 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,18 @@
3131
* @template TValue
3232
* @template-extends Array_<TKey,TValue>
3333
* @template-implements MapInterface<TKey,TValue>
34+
* @psalm-immutable
3435
*/
3536
abstract class Map extends Array_ implements MapInterface
3637
{
38+
/**
39+
* @psalm-param array<TKey,TValue> $data
40+
*/
41+
public function __construct(array $data = [])
42+
{
43+
parent::__construct($data);
44+
}
45+
3746
public function merge(...$stack): MapInterface
3847
{
3948
$instance = clone $this;
@@ -46,15 +55,16 @@ public function merge(...$stack): MapInterface
4655

4756
public function sort(?callable $callback = null): MapInterface
4857
{
49-
$data = $this->data;
5058
$instance = clone $this;
59+
$data = $instance->data;
5160
if ($callback === null) {
5261
asort($data, SORT_NATURAL);
5362
$instance->data = $data;
5463

5564
return $instance;
5665
}
5766

67+
/** @psalm-suppress ImpureFunctionCall */
5868
uasort($data, $callback);
5969
$instance->data = $data;
6070

@@ -63,13 +73,20 @@ public function sort(?callable $callback = null): MapInterface
6373

6474
public function diffKeys(MapInterface $other, ?callable $keyComparator = null): MapInterface
6575
{
66-
$instance = clone $this;
67-
$otherData = $other->toNativeArray();
76+
$instance = clone $this;
77+
$otherData = $other->toNativeArray();
78+
$keyComparator = $keyComparator ?? $this->keyComparator();
6879

69-
/** @psalm-var array<TKey,TValue> $diff1 */
70-
$diff1 = array_diff_ukey($this->data, $otherData, $keyComparator ?? $this->keyComparator());
71-
/** @psalm-var array<TKey,TValue> $diff2 */
72-
$diff2 = array_diff_ukey($otherData, $this->data, $keyComparator ?? $this->keyComparator());
80+
/**
81+
* @psalm-var array<TKey,TValue> $diff1
82+
* @psalm-suppress ImpureFunctionCall
83+
*/
84+
$diff1 = array_diff_ukey($instance->data, $otherData, $keyComparator);
85+
/**
86+
* @psalm-var array<TKey,TValue> $diff2
87+
* @psalm-suppress ImpureFunctionCall
88+
*/
89+
$diff2 = array_diff_ukey($otherData, $instance->data, $keyComparator);
7390
$merged = array_merge(
7491
$diff1,
7592
$diff2
@@ -97,22 +114,22 @@ public function toOrderedList(?callable $sorter = null): OrderedListInterface
97114
}
98115

99116
$data = $this->data;
117+
118+
/** @psalm-suppress ImpureFunctionCall */
100119
usort($data, $sorter);
101120

102121
return new GenericOrderedList($data);
103122
}
104123

105124
public function filter(callable $callback): MapInterface
106125
{
107-
$instance = clone $this;
108-
$instance->data = array_filter($this->data, $callback, ARRAY_FILTER_USE_BOTH);
126+
$instance = clone $this;
127+
/** @psalm-suppress ImpureFunctionCall */
128+
$instance->data = array_filter($instance->data, $callback, ARRAY_FILTER_USE_BOTH);
109129

110130
return $instance;
111131
}
112132

113-
/**
114-
* @psalm-mutation-free
115-
*/
116133
public function keys(): OrderedListInterface
117134
{
118135
$keys = array_keys($this->data);
@@ -128,9 +145,6 @@ public function put($key, $value): MapInterface
128145
return $instance;
129146
}
130147

131-
/**
132-
* @psalm-mutation-free
133-
*/
134148
public function get(string $key)
135149
{
136150
if (! $this->has($key)) {
@@ -157,7 +171,10 @@ public function intersect(MapInterface $other, ?callable $valueComparator = null
157171
private function intersection(MapInterface $other, ?callable $valueComparator, ?callable $keyComparator): array
158172
{
159173
if ($valueComparator && $keyComparator) {
160-
/** @psalm-var array<TKey,TValue> $intersection */
174+
/**
175+
* @psalm-var array<TKey,TValue> $intersection
176+
* @psalm-suppress ImpureFunctionCall
177+
*/
161178
$intersection = array_uintersect_uassoc(
162179
$this->data,
163180
$other->toNativeArray(),
@@ -169,7 +186,10 @@ private function intersection(MapInterface $other, ?callable $valueComparator, ?
169186
}
170187

171188
if ($keyComparator) {
172-
/** @psalm-var array<TKey,TValue> $intersection */
189+
/**
190+
* @psalm-var array<TKey,TValue> $intersection
191+
* @psalm-suppress ImpureFunctionCall
192+
*/
173193
$intersection = array_intersect_ukey($this->data, $other->toNativeArray(), $keyComparator);
174194

175195
return $intersection;
@@ -179,7 +199,10 @@ private function intersection(MapInterface $other, ?callable $valueComparator, ?
179199
$valueComparator = $this->valueComparator();
180200
}
181201

182-
/** @psalm-var array<TKey,TValue> $intersection */
202+
/**
203+
* @psalm-var array<TKey,TValue> $intersection
204+
* @psalm-suppress ImpureFunctionCall
205+
*/
183206
$intersection = array_uintersect($this->data, $other->toNativeArray(), $valueComparator);
184207

185208
return $intersection;
@@ -214,14 +237,20 @@ public function intersectUserAssoc(
214237

215238
public function diff(MapInterface $other, ?callable $valueComparator = null): MapInterface
216239
{
217-
/** @psalm-var array<TKey,TValue> $diff1 */
240+
/**
241+
* @psalm-var array<TKey,TValue> $diff1
242+
* @psalm-suppress ImpureFunctionCall
243+
*/
218244
$diff1 = array_udiff(
219245
$this->toNativeArray(),
220246
$other->toNativeArray(),
221247
$valueComparator ?? $this->valueComparator()
222248
);
223249

224-
/** @psalm-var array<TKey,TValue> $diff2 */
250+
/**
251+
* @psalm-var array<TKey,TValue> $diff2
252+
* @psalm-suppress ImpureFunctionCall
253+
*/
225254
$diff2 = array_udiff(
226255
$other->toNativeArray(),
227256
$this->toNativeArray(),
@@ -263,12 +292,12 @@ public function removeElement($element): MapInterface
263292

264293
public function map(callable $callback): MapInterface
265294
{
266-
return new GenericMap(array_map($callback, $this->data));
295+
$instance = clone $this;
296+
297+
/** @psalm-suppress ImpureFunctionCall */
298+
return new GenericMap(array_map($callback, $instance->data));
267299
}
268300

269-
/**
270-
* @psalm-mutation-free
271-
*/
272301
public function has(string $key): bool
273302
{
274303
return array_key_exists($key, $this->data);

src/MapInterface.php

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ public function unset($key): MapInterface;
8181

8282
/**
8383
* @psalm-return OrderedListInterface<TKey>
84-
* @psalm-mutation-free
8584
*/
8685
public function keys(): OrderedListInterface;
8786

@@ -96,7 +95,6 @@ public function put($key, $value): MapInterface;
9695
* @psalm-param TKey $key
9796
* @psalm-return TValue
9897
* @throws OutOfBoundsException if key does not exist.
99-
* @psalm-mutation-free
10098
*/
10199
public function get(string $key);
102100

@@ -128,7 +126,6 @@ public function intersectUserAssoc(
128126

129127
/**
130128
* @psalm-param TKey $key
131-
* @psalm-mutation-free
132129
*/
133130
public function has(string $key): bool;
134131

0 commit comments

Comments
 (0)