From daae019a973d81e79f56aed6251561e566c94303 Mon Sep 17 00:00:00 2001 From: Jonathan Taylor Date: Fri, 10 Oct 2025 15:58:33 +0100 Subject: [PATCH 1/5] Switch to github actions --- .editorconfig | 3 +++ .github/workflows/tests.yml | 39 +++++++++++++++++++++++++++++++++++++ .travis.yml | 10 ---------- 3 files changed, 42 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/tests.yml delete mode 100644 .travis.yml diff --git a/.editorconfig b/.editorconfig index f42b443..277f652 100644 --- a/.editorconfig +++ b/.editorconfig @@ -6,5 +6,8 @@ insert_final_newline = true indent_style = tab indent_size = 4 +[*.yml] +indent_size = 2 + [*.md] indent_style = space diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..082540a --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,39 @@ +name: Unit Tests + +on: + push: + pull_request: + +jobs: + tests: + name: Unit Tests + runs-on: ubuntu-24.04 + strategy: + matrix: + include: + - php: '8.0' + - php: '8.1' + - php: '8.2' + - php: '8.3' + - php: '8.4' + steps: + - uses: actions/checkout@v4 + + - name: Cache Composer dependencies + uses: actions/cache@v3 + with: + path: ./vendor + key: composer-${{ runner.os }}-${{ hashFiles('**/composer.json') }} + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + coverage: "none" + php-version: "${{ matrix.php }}" + + - name: Install dependencies + run: composer install + + - name: Test + run: | + composer test diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index b80f894..0000000 --- a/.travis.yml +++ /dev/null @@ -1,10 +0,0 @@ -language: php -php: - - 7.0 - - 7.1 - - 7.2 - - 7.3 - - 7.4 - -install: composer install -script: composer test From 3ed61f37253ff05f3fb774080ce8e952ba95f711 Mon Sep 17 00:00:00 2001 From: Jonathan Taylor Date: Fri, 10 Oct 2025 16:12:00 +0100 Subject: [PATCH 2/5] Update phpunit --- .gitignore | 1 + composer.json | 4 ++-- phpunit.xml.dist | 18 +++++++++++------- test/ChainTest.php | 3 ++- test/CountTest.php | 9 +++++---- test/Dataset.php | 2 +- test/FindTest.php | 9 +++++---- test/FirstTest.php | 9 +++++---- test/GetTest.php | 23 ++++++++++++----------- test/HasTest.php | 7 ++++--- test/PushTest.php | 7 ++++--- test/SetTest.php | 26 +++++++++++++------------- 12 files changed, 65 insertions(+), 53 deletions(-) diff --git a/.gitignore b/.gitignore index f7f520e..01399ca 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .idea /vendor/ composer.lock +.phpunit.result.cache diff --git a/composer.json b/composer.json index 523164f..fe3d4bd 100644 --- a/composer.json +++ b/composer.json @@ -13,10 +13,10 @@ "test": "phpunit" }, "require": { - "php": "^7.0|^8.0" + "php": "^8.0" }, "require-dev": { - "phpunit/phpunit": "^6.5|^7.5" + "phpunit/phpunit": "^9.6|^10.5|^11.5|^12.4" }, "autoload": { "psr-4": { diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 84bbf6a..9631cef 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,13 +1,17 @@ - - + - + ./test - - + + ./src - - + + diff --git a/test/ChainTest.php b/test/ChainTest.php index b446456..39bd071 100644 --- a/test/ChainTest.php +++ b/test/ChainTest.php @@ -3,13 +3,14 @@ namespace Noj\Dot\Test; use Noj\Dot\Dot; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; class ChainTest extends TestCase { use Dataset; - /** @test */ + #[Test] public function it_can_find_push_and_select() { $items = Dot::from($this->data) diff --git a/test/CountTest.php b/test/CountTest.php index a315aba..e5dfe05 100644 --- a/test/CountTest.php +++ b/test/CountTest.php @@ -2,6 +2,7 @@ namespace Noj\Dot\Test; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use function Noj\Dot\count; @@ -9,28 +10,28 @@ class CountTest extends TestCase { use Dataset; - /** @test */ + #[Test] public function it_can_count_top_level() { $count = count($this->data, 'groups'); self::assertEquals(2, $count); } - /** @test */ + #[Test] public function it_can_count_nested() { $count = count($this->data, 'groups.0.users'); self::assertEquals(3, $count); } - /** @test */ + #[Test] public function it_can_count_with_wildcard() { $count = count($this->data, 'groups.*.users'); self::assertEquals(4, $count); } - /** @test */ + #[Test] public function it_handles_invalid_path() { $count = count($this->data, 'foo'); diff --git a/test/Dataset.php b/test/Dataset.php index b429fc0..04b1e11 100644 --- a/test/Dataset.php +++ b/test/Dataset.php @@ -6,7 +6,7 @@ trait Dataset { private $data = []; - protected function setUp() + protected function setUp(): void { $this->data = [ 'groups' => [[ diff --git a/test/FindTest.php b/test/FindTest.php index ec167ee..3bcc036 100644 --- a/test/FindTest.php +++ b/test/FindTest.php @@ -2,6 +2,7 @@ namespace Noj\Dot\Test; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use function Noj\Dot\find; @@ -9,7 +10,7 @@ class FindTest extends TestCase { use Dataset; - /** @test */ + #[Test] public function it_can_find_property_by_value() { $found = find($this->data, 'groups.*.users.*.banned', true); @@ -36,7 +37,7 @@ public function it_can_find_property_by_value() ); } - /** @test */ + #[Test] public function it_can_find_property_by_callable() { $found = find($this->data, 'groups.*.users.*.id', function (int $id) { @@ -60,7 +61,7 @@ public function it_can_find_property_by_callable() ); } - /** @test */ + #[Test] public function it_can_find_item_by_callable() { $found = find($this->data, 'groups.*.users.*', function (array $user) { @@ -79,7 +80,7 @@ public function it_can_find_item_by_callable() ); } - /** @test */ + #[Test] public function it_returns_empty_array_if_no_matches() { $found = find($this->data, 'groups.*.users.*.foo', 'bar'); diff --git a/test/FirstTest.php b/test/FirstTest.php index 2d49286..86c40b6 100644 --- a/test/FirstTest.php +++ b/test/FirstTest.php @@ -3,6 +3,7 @@ namespace Noj\Dot\Test; use Noj\Dot\Dot; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use function Noj\Dot\first; @@ -10,7 +11,7 @@ class FirstTest extends TestCase { use Dataset; - /** @test */ + #[Test] public function it_returns_first_match_by_value() { $result = first($this->data, 'groups.*.users.*.banned', true); @@ -18,7 +19,7 @@ public function it_returns_first_match_by_value() self::assertEquals($this->data['groups'][0]['users'][1], $result); } - /** @test */ + #[Test] public function it_returns_first_match_by_callable() { $result = first($this->data, 'groups.*.users.*', function (array $user) { @@ -28,7 +29,7 @@ public function it_returns_first_match_by_callable() self::assertEquals($this->data['groups'][0]['users'][1], $result); } - /** @test */ + #[Test] public function it_returns_null_if_no_match() { $result = first($this->data, 'groups.*.users.*.banned', 'foo'); @@ -36,7 +37,7 @@ public function it_returns_null_if_no_match() self::assertNull($result); } - /** @test */ + #[Test] public function it_returns_first_index() { $result = Dot::from($this->data['groups'][0]['users'])->first()->get(); diff --git a/test/GetTest.php b/test/GetTest.php index 383204f..d66b6ea 100644 --- a/test/GetTest.php +++ b/test/GetTest.php @@ -3,12 +3,13 @@ namespace Noj\Dot\Test; use Noj\Dot\Test\Stubs\Collection; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use function Noj\Dot\get; class GetTest extends TestCase { - /** @test */ + #[Test] public function it_can_get_a_top_level_property() { $data = ['property' => ['foo' => 'bar']]; @@ -24,7 +25,7 @@ public function it_can_get_a_top_level_property() self::assertEquals('foo', $value); } - /** @test */ + #[Test] public function it_can_get_path_through_arrays() { $data = [ @@ -37,7 +38,7 @@ public function it_can_get_path_through_arrays() self::assertEquals('value', $value); } - /** @test */ + #[Test] public function it_can_get_path_through_array_like_objects() { $items = new Collection(['name' => 'item1']); @@ -47,7 +48,7 @@ public function it_can_get_path_through_array_like_objects() self::assertEquals('item1', $value); } - /** @test */ + #[Test] public function it_returns_null_if_array_path_doesnt_exist() { $data = [ @@ -62,7 +63,7 @@ public function it_returns_null_if_array_path_doesnt_exist() self::assertArrayNotHasKey('foo', $data['key']); } - /** @test */ + #[Test] public function it_returns_null_if_object_path_doesnt_exist() { $data = (object)[ @@ -73,11 +74,11 @@ public function it_returns_null_if_object_path_doesnt_exist() self::assertNull(get($data, 'key.foo')); self::assertNull(get($data, 'key.foo.bar')); self::assertNull(get($data, 'key.foo.bar.baz')); - self::assertObjectNotHasAttribute('foo', $data); - self::assertObjectNotHasAttribute('foo', $data->key); + self::assertObjectNotHasProperty('foo', $data); + self::assertObjectNotHasProperty('foo', $data->key); } - /** @test */ + #[Test] public function it_can_get_path_through_objects() { $data = [ @@ -92,7 +93,7 @@ public function it_can_get_path_through_objects() self::assertEquals('value', $value); } - /** @test */ + #[Test] public function it_can_traverse_through_getters() { $data = [ @@ -118,7 +119,7 @@ public function getSomething() { self::assertEquals('value', $value); } - /** @test */ + #[Test] public function it_returns_null_if_getter_doesnt_exist() { $data = ['key' => []]; @@ -129,7 +130,7 @@ public function it_returns_null_if_getter_doesnt_exist() self::assertNull(get($data, 'key.@getSomething.foo')); } - /** @test */ + #[Test] public function it_can_pluck_values_from_multidimensional_path() { $data = [ diff --git a/test/HasTest.php b/test/HasTest.php index 52962b0..cf76b46 100644 --- a/test/HasTest.php +++ b/test/HasTest.php @@ -2,12 +2,13 @@ namespace Noj\Dot\Test; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use function Noj\Dot\has; class HasTest extends TestCase { - /** @test */ + #[Test] public function it_returns_true_if_path_exists() { $data = ['foo' => ['bar' => 'baz']]; @@ -15,7 +16,7 @@ public function it_returns_true_if_path_exists() self::assertTrue(has($data, 'foo.bar')); } - /** @test */ + #[Test] public function it_returns_false_if_path_does_not_exist() { $data = ['foo' => ['bar' => 'baz']]; @@ -23,7 +24,7 @@ public function it_returns_false_if_path_does_not_exist() self::assertFalse(has($data, 'foo.baz')); } - /** @test */ + #[Test] public function it_can_check_multidimensional_paths() { $data = [ diff --git a/test/PushTest.php b/test/PushTest.php index d7ad23f..a2f62d9 100644 --- a/test/PushTest.php +++ b/test/PushTest.php @@ -2,12 +2,13 @@ namespace Noj\Dot\Test; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use function Noj\Dot\push; class PushTest extends TestCase { - /** @test */ + #[Test] public function it_should_push_onto_array() { $data = ['items' => ['item1', 'item2']]; @@ -17,7 +18,7 @@ public function it_should_push_onto_array() self::assertEquals(['item1', 'item2', 'item3'], $items); } - /** @test */ + #[Test] public function it_can_push_with_wildcard() { $users = [ @@ -31,7 +32,7 @@ public function it_can_push_with_wildcard() self::assertEquals(['item1', 'item2'], $users[1]['items']); } - /** @test */ + #[Test] public function it_does_nothing_if_array_doesnt_exist() { $data = []; diff --git a/test/SetTest.php b/test/SetTest.php index 9b49a02..c269ef3 100644 --- a/test/SetTest.php +++ b/test/SetTest.php @@ -2,12 +2,13 @@ namespace Noj\Dot\Test; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use function Noj\Dot\set; class SetTest extends TestCase { - /** @test */ + #[Test] public function it_can_set_path_through_arrays() { $data = [ @@ -22,7 +23,7 @@ public function it_can_set_path_through_arrays() self::assertEquals('foo', $data['nested']['data']['property']); } - /** @test */ + #[Test] public function it_can_set_path_through_objects() { $data = [ @@ -37,7 +38,7 @@ public function it_can_set_path_through_objects() self::assertEquals('foo', $data['nested']->data->property); } - /** @test */ + #[Test] public function it_can_create_keys_if_missing() { $data = []; @@ -46,7 +47,7 @@ public function it_can_create_keys_if_missing() self::assertEquals(2, $data['key']['foo']->bar['baz']); } - /** @test */ + #[Test] public function it_can_accept_array_to_set_multiple_paths() { $data = [ @@ -69,7 +70,7 @@ public function it_can_accept_array_to_set_multiple_paths() self::assertEquals('bar', $data['nested']['another']['property']); } - /** @test */ + #[Test] public function it_can_call_setter() { $data = [ @@ -90,7 +91,7 @@ public function setValue($value) { self::assertEquals('value', $data['nested']['property']->getValue()); } - /** @test */ + #[Test] public function it_can_call_setter_multiple_times() { $data = [ @@ -111,19 +112,18 @@ public function addValue($value) { self::assertEquals(['foo', 'bar', 'baz'], $data['nested']['property']->getValues()); } - /** - * @test - * @expectedException \Noj\Dot\Exception\InvalidMethodException - * @expectedExceptionMessage Can't call method setValue on array - */ + #[Test] public function it_throws_exception_if_setter_not_callable() { + $this->expectException(\Noj\Dot\Exception\InvalidMethodException::class); + $this->expectExceptionMessage("Can't call method setValue on array"); + $data = []; set($data, 'property.ddd.@setValue', 'value'); } - /** @test */ + #[Test] public function it_can_set_values_on_multidimensional_path() { $data = [ @@ -160,7 +160,7 @@ public function it_can_set_values_on_multidimensional_path() self::assertEquals('sameName', $data[2]['items'][1]['name']); } - /** @test */ + #[Test] public function it_can_handle_expand_as_last_key() { $data = [ From 2704298a1f5c102ab39e5ee730facf0a6b78c0d6 Mon Sep 17 00:00:00 2001 From: Jonathan Taylor Date: Mon, 13 Oct 2025 12:58:13 +0100 Subject: [PATCH 3/5] Add more types and fix implicit nullable deprecations --- src/Dot.php | 38 ++++++++++++++++++-------------------- src/Parser/Node.php | 14 ++++---------- src/Parser/NodeList.php | 9 ++------- src/Parser/Parser.php | 10 ++++------ src/Parser/Segment.php | 11 +++-------- src/functions.php | 14 +++++++------- 6 files changed, 38 insertions(+), 58 deletions(-) diff --git a/src/Dot.php b/src/Dot.php index 209df5a..b6365e0 100644 --- a/src/Dot.php +++ b/src/Dot.php @@ -9,14 +9,11 @@ class Dot { - private $data; - - public function __construct(&$data) + public function __construct(private mixed &$data) { - $this->data = &$data; } - public static function from(&$data): self + public static function from(array|object &$data): self { return new self($data); } @@ -27,7 +24,7 @@ public function count(string $path = null): int return is_array($values) ? \count(array_filter($values)) : 0; } - public function find(string $path, $equals): self + public function find(string $path, mixed $equals): self { $parser = new Parser(); $nodeList = $parser->parse($this->data, $path); @@ -67,26 +64,27 @@ public function first(string $path = null, $equals = null): self return $this->find($path, $equals)->first(); } - /** - * @param null|int|string $path - * - * @return array|mixed|null - */ - public function get($path = null) + public function get(int|string|null $path = null) { if ($path === null) { return $this->data; } - return $this->select($path)->data; + $selected = $this->select($path); + + if ($selected instanceof self) { + return $selected->data; + } + + return $selected; } - public function has(string $path): bool + public function has(int|string $path): bool { return $this->get($path) !== null; } - public function push(string $path, $value): self + public function push(string $path, mixed $value): self { $parser = new Parser(); $nodeList = $parser->parse($this->data, $path); @@ -99,7 +97,7 @@ public function push(string $path, $value): self return $this; } - public function set($paths, $value = null) + public function set(array|string $paths, mixed $value = null) { if (is_array($paths)) { foreach ($paths as $path => $pathValue) { @@ -137,9 +135,9 @@ public function set($paths, $value = null) } } - private function select($path): self + private function select(int|string $path): mixed { - if (is_int($path)) { + if (is_numeric($path)) { $value = $this->data[$path] ?? null; return new self($value); } @@ -168,7 +166,7 @@ private function select($path): self return new self($flattened); } - private function equality($value): callable + private function equality(mixed $value): callable { return function ($item) use ($value) { return $item === $value; @@ -188,7 +186,7 @@ private function flatten(array &$values): array return $flattened; } - private function &wrap(&$value): array + private function &wrap(mixed &$value): array { if (is_array($value)) { return $value; diff --git a/src/Parser/Node.php b/src/Parser/Node.php index c7be0ce..329e9d5 100644 --- a/src/Parser/Node.php +++ b/src/Parser/Node.php @@ -6,13 +6,8 @@ class Node { - public $item; - public $segment; - - public function __construct(&$item, Segment $segment) + public function __construct(public array|object &$item, public Segment $segment) { - $this->item = &$item; - $this->segment = $segment; } public function withSegment(Segment $segment): Node @@ -22,9 +17,8 @@ public function withSegment(Segment $segment): Node /** * @throws InvalidMethodException - * @return mixed|null */ - public function &accessValue($initialiseIfNotSet = false) + public function &accessValue($initialiseIfNotSet = false): mixed { if ($method = $this->getMethod()) { $result = $method ? $method->invoke($this->item) : null; @@ -52,7 +46,7 @@ public function &accessValue($initialiseIfNotSet = false) return $this->item->{$this->segment->key}; } - public function getMethod() + public function getMethod(): ?\ReflectionMethod { if (!$this->isMethodCall()) { return null; @@ -72,7 +66,7 @@ public function isMethodCall(): bool return strpos($this->segment->key, '@') === 0; } - public function getMethodName() + public function getMethodName(): string { return substr($this->segment->key, 1); } diff --git a/src/Parser/NodeList.php b/src/Parser/NodeList.php index 81c4fd0..70eb06d 100644 --- a/src/Parser/NodeList.php +++ b/src/Parser/NodeList.php @@ -5,14 +5,9 @@ class NodeList { /** @var (self|Node)[] */ - public $items = []; + public array $items = []; - /** - * @param self|Node $item - * - * @return self - */ - public function add($item): self + public function add(Node|self $item): self { $this->items[] = $item; return $this; diff --git a/src/Parser/Parser.php b/src/Parser/Parser.php index 6d6c89e..6b2d316 100644 --- a/src/Parser/Parser.php +++ b/src/Parser/Parser.php @@ -6,15 +6,13 @@ class Parser { - private $createMissingPaths; - public $branched = false; + public bool $branched = false; - public function __construct($createMissingPaths = false) + public function __construct(private bool $createMissingPaths = false) { - $this->createMissingPaths = $createMissingPaths; } - public function parse(&$data, string $path): NodeList + public function parse(array|object &$data, string $path): NodeList { $segments = $this->getSegments($path); @@ -72,7 +70,7 @@ private function getSegments(string $path): array $segments = []; foreach ($iterator as $index => $part) { - $segments[] = new Segment($part, $iterator[$index + 1] ?? Segment::DELIMITER_ARRAY); + $segments[] = new Segment($part, $iterator[$index + 1] ?? Segment::DELIMITER_ARRAY); $iterator->next(); } diff --git a/src/Parser/Segment.php b/src/Parser/Segment.php index d298ac4..51606ed 100644 --- a/src/Parser/Segment.php +++ b/src/Parser/Segment.php @@ -4,15 +4,10 @@ class Segment { - const DELIMITER_ARRAY = '.'; - const DELIMITER_OBJECT = '->'; + public const DELIMITER_ARRAY = '.'; + public const DELIMITER_OBJECT = '->'; - public $key; - public $delimiter; - - public function __construct(string $key, string $delimiter = self::DELIMITER_ARRAY) + public function __construct(public string $key, public string $delimiter = self::DELIMITER_ARRAY) { - $this->key = $key; - $this->delimiter = $delimiter; } } diff --git a/src/functions.php b/src/functions.php index 4962220..65d9b6f 100644 --- a/src/functions.php +++ b/src/functions.php @@ -2,43 +2,43 @@ namespace Noj\Dot; -function count($data, string $path): int +function count(array|object $data, string $path): int { return Dot::from($data)->count($path); } -function find(&$data, string $path, $equals) +function find(array|object &$data, string $path, $equals): mixed { return Dot::from($data) ->find($path, $equals) ->get(); } -function first(&$data, string $path = null, $equals = null) +function first(array|object &$data, ?string $path = null, $equals = null): mixed { return Dot::from($data) ->first($path, $equals) ->get(); } -function get($data, $path) +function get(array|object $data, int|string|null $path = null): mixed { return Dot::from($data)->get($path); } -function has($data, string $path): bool +function has(array|object $data, int|string $path): bool { return Dot::from($data)->has($path); } -function push(&$data, string $path, $value) +function push(array|object &$data, string $path, mixed $value): mixed { return Dot::from($data) ->push($path, $value) ->get($path); } -function set(&$data, $paths, $value = null) +function set(array|object &$data, array|string $paths, mixed $value = null): void { Dot::from($data)->set($paths, $value); } From 10912d2ca9f94b3469746e4e62b9f0612fbc7b6a Mon Sep 17 00:00:00 2001 From: Jonathan Taylor Date: Mon, 13 Oct 2025 13:09:52 +0100 Subject: [PATCH 4/5] Simplify --- src/Exception/InvalidMethodException.php | 2 +- src/Parser/Node.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Exception/InvalidMethodException.php b/src/Exception/InvalidMethodException.php index 47e5b25..d775c66 100644 --- a/src/Exception/InvalidMethodException.php +++ b/src/Exception/InvalidMethodException.php @@ -8,7 +8,7 @@ class InvalidMethodException extends DotException { public static function fromNode(Node $node): self { - $type = is_object($node->item) ? get_class($node->item) : gettype($node->item); + $type = get_debug_type($node->item); return new self("Can't call method {$node->getMethodName()} on $type"); } } diff --git a/src/Parser/Node.php b/src/Parser/Node.php index 329e9d5..138253e 100644 --- a/src/Parser/Node.php +++ b/src/Parser/Node.php @@ -21,7 +21,7 @@ public function withSegment(Segment $segment): Node public function &accessValue($initialiseIfNotSet = false): mixed { if ($method = $this->getMethod()) { - $result = $method ? $method->invoke($this->item) : null; + $result = $method?->invoke($this->item); return $result; } From 4672122797f23bacf6dbc3749fb9087df441c5c9 Mon Sep 17 00:00:00 2001 From: Jonathan Taylor Date: Mon, 13 Oct 2025 13:03:25 +0100 Subject: [PATCH 5/5] Use arrow functions --- README.md | 4 +--- src/Dot.php | 4 +--- src/Parser/NodeList.php | 7 ++++--- src/Parser/Parser.php | 5 +---- test/FindTest.php | 20 ++++++++++++-------- test/FirstTest.php | 10 ++++++---- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 13727e8..0273e16 100644 --- a/README.md +++ b/README.md @@ -108,9 +108,7 @@ Find the first item that passes the given truth test. ```php $dot->first('groups.*.items.*.rare', true)->get(); // ['name' => 'item3', 'rare' => true] -$dot->first('groups.*.items.*', function (array $item) { - return $item['rare'] === true; -})->get(); // same as above +$dot->first('groups.*.items.*', fn (array $item) => $item['rare'] === true)->get(); // same as above ``` #### `Dot::get(null|int|string $path): mixed` diff --git a/src/Dot.php b/src/Dot.php index b6365e0..6fd429b 100644 --- a/src/Dot.php +++ b/src/Dot.php @@ -168,9 +168,7 @@ private function select(int|string $path): mixed private function equality(mixed $value): callable { - return function ($item) use ($value) { - return $item === $value; - }; + return static fn($item) => $item === $value; } private function flatten(array &$values): array diff --git a/src/Parser/NodeList.php b/src/Parser/NodeList.php index 70eb06d..9aff0d3 100644 --- a/src/Parser/NodeList.php +++ b/src/Parser/NodeList.php @@ -18,9 +18,10 @@ public function add(Node|self $item): self */ public function getLeafNodes(): array { - $nodes = array_map(function ($item) { - return $item instanceof self ? $item->getLeafNodes() : [$item]; - }, $this->items); + $nodes = array_map( + static fn($item) => $item instanceof self ? $item->getLeafNodes() : [$item], + $this->items + ); return array_merge([], ...$nodes); } diff --git a/src/Parser/Parser.php b/src/Parser/Parser.php index 6b2d316..c59285b 100644 --- a/src/Parser/Parser.php +++ b/src/Parser/Parser.php @@ -15,10 +15,7 @@ public function __construct(private bool $createMissingPaths = false) public function parse(array|object &$data, string $path): NodeList { $segments = $this->getSegments($path); - - $keys = array_map(function (Segment $segment) { - return $segment->key; - }, $segments); + $keys = array_map(static fn(Segment $segment) => $segment->key, $segments); $this->branched = in_array('*', $keys); diff --git a/test/FindTest.php b/test/FindTest.php index 3bcc036..0037659 100644 --- a/test/FindTest.php +++ b/test/FindTest.php @@ -38,11 +38,13 @@ public function it_can_find_property_by_value() } #[Test] - public function it_can_find_property_by_callable() + public function it_can_find_property_by_closure_condition() { - $found = find($this->data, 'groups.*.users.*.id', function (int $id) { - return $id < 3; - }); + $found = find( + $this->data, + 'groups.*.users.*.id', + fn(int $id) => $id < 3 + ); self::assertEquals( [ @@ -62,11 +64,13 @@ public function it_can_find_property_by_callable() } #[Test] - public function it_can_find_item_by_callable() + public function it_can_find_item_by_closure_condition() { - $found = find($this->data, 'groups.*.users.*', function (array $user) { - return $user['id'] < 3 && $user['banned']; - }); + $found = find( + $this->data, + 'groups.*.users.*', + fn(array $user) => $user['id'] < 3 && $user['banned'] + ); self::assertEquals( [ diff --git a/test/FirstTest.php b/test/FirstTest.php index 86c40b6..5acf5ab 100644 --- a/test/FirstTest.php +++ b/test/FirstTest.php @@ -20,11 +20,13 @@ public function it_returns_first_match_by_value() } #[Test] - public function it_returns_first_match_by_callable() + public function it_returns_first_match_by_closure_condition() { - $result = first($this->data, 'groups.*.users.*', function (array $user) { - return $user['id'] > 1; - }); + $result = first( + $this->data, + 'groups.*.users.*', + fn(array $user) => $user['id'] > 1 + ); self::assertEquals($this->data['groups'][0]['users'][1], $result); }