Skip to content

Commit bf2f0bd

Browse files
authored
Merge pull request #29 from colinodell/throw-exception-on-missing-key
Throw exception when accessing non-existent key paths and not providing a default value
2 parents a3314cd + c383e69 commit bf2f0bd

File tree

5 files changed

+77
-10
lines changed

5 files changed

+77
-10
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ $data->has('a.b.c');
4141

4242
// false
4343
$data->has('a.b.d.j');
44+
45+
46+
// 'some-default-value'
47+
$data->get('some.path.that.does.not.exist', 'some-default-value');
48+
49+
// throws a MissingPathException because no default was given
50+
$data->get('some.path.that.does.not.exist');
4451
```
4552

4653
A more concrete example:

src/Data.php

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use ArrayAccess;
1717
use Dflydev\DotAccessData\Exception\DataException;
1818
use Dflydev\DotAccessData\Exception\InvalidPathException;
19+
use Dflydev\DotAccessData\Exception\MissingPathException;
1920

2021
/**
2122
* @implements ArrayAccess<string, mixed>
@@ -116,16 +117,21 @@ public function remove(string $key): void
116117
*/
117118
public function get(string $key, $default = null)
118119
{
120+
/** @psalm-suppress ImpureFunctionCall */
121+
$hasDefault = \func_num_args() > 1;
122+
119123
$currentValue = $this->data;
120124
$keyPath = self::keyToPathArray($key);
121125

122126
foreach ($keyPath as $currentKey) {
123-
if (!isset($currentValue[$currentKey])) {
124-
return $default;
125-
}
126-
if (!is_array($currentValue)) {
127-
return $default;
127+
if (!is_array($currentValue) || !isset($currentValue[$currentKey])) {
128+
if ($hasDefault) {
129+
return $default;
130+
}
131+
132+
throw new MissingPathException($key, sprintf('No data exists at the given path: "%s"', self::formatPath($keyPath)));
128133
}
134+
129135
$currentValue = $currentValue[$currentKey];
130136
}
131137

@@ -208,7 +214,7 @@ public function offsetExists($key)
208214
*/
209215
public function offsetGet($key)
210216
{
211-
return $this->get($key);
217+
return $this->get($key, null);
212218
}
213219

214220
/**

src/DataInterface.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,16 @@ public function remove(string $key): void;
5858
/**
5959
* Get the raw value for a key
6060
*
61-
* If the key does not exist, the provided default value (or null) will be returned instead.
61+
* If the key does not exist, an optional default value can be returned instead.
62+
* If no default is provided then an exception will be thrown instead.
6263
*
6364
* @param string $key
6465
* @param mixed $default
6566
*
6667
* @return mixed
6768
*
6869
* @throws InvalidPathException if the given key is empty
70+
* @throws InvalidPathException if the given key does not exist and no default value was given
6971
*
7072
* @psalm-mutation-free
7173
*/
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is a part of dflydev/dot-access-data.
7+
*
8+
* (c) Dragonfly Development Inc.
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespace Dflydev\DotAccessData\Exception;
15+
16+
use Throwable;
17+
18+
/**
19+
* Thrown when trying to access a path that does not exist
20+
*/
21+
class MissingPathException extends DataException
22+
{
23+
/** @var string */
24+
protected $path;
25+
26+
public function __construct(string $path, string $message = '', int $code = 0, Throwable $previous = null)
27+
{
28+
$this->path = $path;
29+
30+
parent::__construct($message, $code, $previous);
31+
}
32+
33+
public function getPath(): string
34+
{
35+
return $this->path;
36+
}
37+
}

tests/DataTest.php

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,9 @@ public function testRemove()
143143
$data->remove('d.e.f');
144144
$data->remove('empty.path');
145145

146-
$this->assertNull($data->get('a'));
147-
$this->assertNull($data->get('b/c'));
148-
$this->assertNull($data->get('b.d.d3'));
146+
$this->assertNull($data->get('a', null));
147+
$this->assertNull($data->get('b/c', null));
148+
$this->assertNull($data->get('b.d.d3', null));
149149
$this->assertNull(null);
150150
$this->assertEquals('D2', $data->get('b.d.d2'));
151151

@@ -161,6 +161,21 @@ public function testGet()
161161
$this->runSampleDataTests($data);
162162
}
163163

164+
public function testGetWhenValueDoesNotExist()
165+
{
166+
$data = new Data($this->getSampleData());
167+
168+
// With a default parameter given:
169+
$this->assertSame('DEFAULT', $data->get('foo.bar', 'DEFAULT'));
170+
$this->assertSame(false, $data->get('foo.bar', false));
171+
$this->assertSame(null, $data->get('foo/bar', null));
172+
173+
// Without a default parameter:
174+
$this->expectException(DataException::class);
175+
$this->expectExceptionMessage('No data exists at the given path: "foo » bar"');
176+
$data->get('foo.bar');
177+
}
178+
164179
public function testHas()
165180
{
166181
$data = new Data($this->getSampleData());

0 commit comments

Comments
 (0)