Skip to content

Commit cc3b0a0

Browse files
authored
Merge pull request #6 from boesing/qa/out-of-bounds-exception-in-favor-of-null
2 parents b57ccea + 6ec46a2 commit cc3b0a0

File tree

8 files changed

+56
-15
lines changed

8 files changed

+56
-15
lines changed

src/ArrayInterface.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Countable;
88
use IteratorAggregate;
9+
use OutOfBoundsException;
910

1011
/**
1112
* @internal
@@ -23,14 +24,16 @@ interface ArrayInterface extends IteratorAggregate, Countable
2324
public function contains($element): bool;
2425

2526
/**
26-
* @psalm-return TValue|null
27+
* @psalm-return TValue
2728
* @psalm-mutation-free
29+
* @throws OutOfBoundsException if there are no values available.
2830
*/
2931
public function first();
3032

3133
/**
32-
* @psalm-return TValue|null
34+
* @psalm-return TValue
3335
* @psalm-mutation-free
36+
* @throws OutOfBoundsException if there are no values available.
3437
*/
3538
public function last();
3639

src/Array_.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use ArrayIterator;
88
use DateTimeInterface;
9+
use OutOfBoundsException;
910
use Traversable;
1011
use Webmozart\Assert\Assert;
1112

@@ -59,8 +60,8 @@ public function contains($element): bool
5960
*/
6061
public function first()
6162
{
62-
if ($this->data === []) {
63-
return null;
63+
if ($this->isEmpty()) {
64+
throw new OutOfBoundsException('There are no values available.');
6465
}
6566

6667
return reset($this->data);
@@ -71,8 +72,8 @@ public function first()
7172
*/
7273
public function last()
7374
{
74-
if ($this->data === []) {
75-
return null;
75+
if ($this->isEmpty()) {
76+
throw new OutOfBoundsException('There are no values available.');
7677
}
7778

7879
return end($this->data);

src/Map.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44

55
namespace Boesing\TypedArrays;
66

7+
use OutOfBoundsException;
78
use Webmozart\Assert\Assert;
89

910
use function array_diff_ukey;
1011
use function array_filter;
1112
use function array_intersect_ukey;
13+
use function array_key_exists;
1214
use function array_keys;
1315
use function array_map;
1416
use function array_merge;
@@ -17,6 +19,7 @@
1719
use function array_uintersect_uassoc;
1820
use function array_values;
1921
use function asort;
22+
use function sprintf;
2023
use function uasort;
2124
use function usort;
2225

@@ -138,7 +141,11 @@ public function put($key, $value): MapInterface
138141
*/
139142
public function get($key)
140143
{
141-
return $this->data[$key] ?? null;
144+
if (! array_key_exists($key, $this->data)) {
145+
throw new OutOfBoundsException(sprintf('There is no value stored for provided key: %s', (string) $key));
146+
}
147+
148+
return $this->data[$key];
142149
}
143150

144151
public function intersect(MapInterface $other, ?callable $valueComparator = null): MapInterface

src/MapInterface.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace Boesing\TypedArrays;
66

7+
use OutOfBoundsException;
8+
79
/**
810
* @template TValue
911
* @template-extends ArrayInterface<string,TValue>
@@ -91,7 +93,8 @@ public function put($key, $value): MapInterface;
9193

9294
/**
9395
* @psalm-param string $key
94-
* @psalm-return TValue|null
96+
* @psalm-return TValue
97+
* @throws OutOfBoundsException if key does not exist.
9598
* @psalm-mutation-free
9699
*/
97100
public function get($key);

src/OrderedList.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use function array_combine;
1212
use function array_fill;
1313
use function array_filter;
14+
use function array_key_exists;
1415
use function array_keys;
1516
use function array_map;
1617
use function array_merge;
@@ -23,6 +24,7 @@
2324
use function is_callable;
2425
use function serialize;
2526
use function sort;
27+
use function sprintf;
2628
use function usort;
2729

2830
use const SORT_NATURAL;
@@ -76,7 +78,11 @@ public function add($element): OrderedListInterface
7678
*/
7779
public function at(int $position)
7880
{
79-
return $this->data[$position] ?? null;
81+
if (! array_key_exists($position, $this->data)) {
82+
throw new OutOfBoundsException(sprintf('There is no value stored in that position: %d', $position));
83+
}
84+
85+
return $this->data[$position];
8086
}
8187

8288
public function sort(?callable $callback = null): OrderedListInterface
@@ -187,7 +193,11 @@ public function unify(
187193

188194
foreach ($instance->data as $value) {
189195
$identifier = $unificationIdentifierGenerator($value);
190-
$unique = $unified->get($identifier) ?? $value;
196+
try {
197+
$unique = $unified->get($identifier);
198+
} catch (OutOfBoundsException $exception) {
199+
$unique = $value;
200+
}
191201

192202
if ($callback) {
193203
$unique = $callback($unique, $value);

src/OrderedListInterface.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ interface OrderedListInterface extends ArrayInterface
2020
public function add($element): OrderedListInterface;
2121

2222
/**
23-
* @psalm-return TValue|null
23+
* @psalm-return TValue
24+
* @throws OutOfBoundsException If position does not exist.
2425
* @psalm-mutation-free
2526
*/
2627
public function at(int $position);

tests/GenericMapTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use DateTimeImmutable;
1010
use Generator;
1111
use Lcobucci\Clock\FrozenClock;
12+
use OutOfBoundsException;
1213
use PHPUnit\Framework\TestCase;
1314
use stdClass;
1415

@@ -459,4 +460,11 @@ public function testCanIntersectWithUserFunctions(): void
459460
->toNativeArray()
460461
);
461462
}
463+
464+
public function testGetThrowsOutOfBoundsExceptionWhenKeyDoesNotExist(): void
465+
{
466+
$map = new GenericMap([]);
467+
$this->expectException(OutOfBoundsException::class);
468+
$map->get('foo');
469+
}
462470
}

tests/GenericOrderedListTest.php

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,8 @@ public function testReturnsNullWhenSpecificItemNotFound(): void
202202
{
203203
$list = new GenericOrderedList([]);
204204

205-
self::assertNull($list->at(0));
205+
$this->expectException(OutOfBoundsException::class);
206+
$list->at(0);
206207
}
207208

208209
/**
@@ -631,11 +632,18 @@ public function testFirstAndLastElementReturnsIdenticalObject(): void
631632
self::assertEquals($object2, $list->last());
632633
}
633634

634-
public function testFirstAndLastReturnNullOnEmptyList(): void
635+
public function testFirstThrowsOutOfBoundsExceptionWhenListIsEmpty(): void
635636
{
636637
$list = new GenericOrderedList([]);
637-
self::assertNull($list->first());
638-
self::assertNull($list->last());
638+
$this->expectException(OutOfBoundsException::class);
639+
$list->first();
640+
}
641+
642+
public function testLastThrowsOutOfBoundsExceptionWhenListIsEmpty(): void
643+
{
644+
$list = new GenericOrderedList([]);
645+
$this->expectException(OutOfBoundsException::class);
646+
$list->last();
639647
}
640648

641649
public function testContainsDoesExactMatch(): void

0 commit comments

Comments
 (0)