Working with Arrays and Filters
This guide focuses on techniques for working with arrays and using filters in Derafu Selector.
- Basic Array Access
- Numeric Indexing
- Filtering Arrays by Condition
- Complex Filtering
- Nested Arrays
- Array Operations
Basic Array Access
Arrays can be accessed using both dot notation and square bracket syntax:
use Derafu\Selector\Selector;
$data = [
'items' => ['apple', 'banana', 'cherry'],
'counts' => [5, 10, 15],
];
// Access entire array.
$allItems = Selector::get($data, 'items');
// ['apple', 'banana', 'cherry']
// First element.
$firstItem = Selector::get($data, 'items[0]');
// 'apple'
// Last element.
$lastItem = Selector::get($data, 'items[2]');
// 'cherry'
// Non-existent index.
$nonExistent = Selector::get($data, 'items[5]');
// null
Numeric Indexing
$data = [
'matrix' => [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
],
];
// Accessing multi-dimensional arrays.
$center = Selector::get($data, 'matrix[1][1]');
// 5
// Alternative dot notation.
$center = Selector::get($data, 'matrix.1.1');
// 5
// Mixed notation.
$firstRow = Selector::get($data, 'matrix[0]');
// [1, 2, 3]
$firstRowThirdElement = Selector::get($data, 'matrix[0][2]');
// 3
Filtering Arrays by Condition
The most powerful feature for array handling is filtering by key/value conditions:
$data = [
'users' => [
['id' => 1, 'name' => 'John', 'role' => 'admin'],
['id' => 2, 'name' => 'Jane', 'role' => 'user'],
['id' => 3, 'name' => 'Bob', 'role' => 'user'],
]
];
// Find user by ID.
$userName = Selector::get($data, 'users[id=2:name]');
// 'Jane'
// Find user by role.
$adminName = Selector::get($data, 'users[role=admin:name]');
// 'John'
// Non-matching filter.
$nonExistent = Selector::get($data, 'users[id=99:name]');
// null
Syntax for Dependent Selectors
The syntax for array filtering with dependent selectors is:
arrayKey[requiredKey=requiredValue:dependentKey]
Where:
arrayKey
is the key containing the array to search in.requiredKey
is the key to match in each array element.requiredValue
is the value thatrequiredKey
should equal.dependentKey
is the key to extract from the matching element.
Complex Filtering
You can combine filters with further navigation:
$data = [
'orders' => [
[
'id' => 1001,
'customer' => 'John',
'items' => [
['product' => 'Laptop', 'price' => 999],
['product' => 'Mouse', 'price' => 25],
],
],
[
'id' => 1002,
'customer' => 'Jane',
'items' => [
['product' => 'Phone', 'price' => 699],
['product' => 'Headphones', 'price' => 149],
],
],
],
];
// Get the first item from order 1002.
$product = Selector::get($data, 'orders[id=1002:items][0].product');
// 'Phone'
// Get the price of the second item from order 1001.
$price = Selector::get($data, 'orders[id=1001:items][1].price');
// 25
// Find an item by product name within an order.
$data = [
'orders' => [
[
'id' => 1001,
'items' => [
['product' => 'Laptop', 'price' => 999],
['product' => 'Mouse', 'price' => 25],
],
],
],
];
$mousePrice = Selector::get($data, 'orders[id=1001:items][product=Mouse:price]');
// 25
Nested Arrays
For deeply nested structures:
$data = [
'departments' => [
[
'name' => 'Engineering',
'teams' => [
[
'name' => 'Frontend',
'members' => [
['id' => 101, 'name' => 'Alice'],
['id' => 102, 'name' => 'Bob'],
]
],
[
'name' => 'Backend',
'members' => [
['id' => 201, 'name' => 'Charlie'],
['id' => 202, 'name' => 'Diana'],
],
],
],
],
],
];
// Find Charlie's ID through the department and team.
$charlieId = Selector::get($data,
'departments[name=Engineering:teams][name=Backend:members][name=Charlie:id]'
); // 201
Array Operations
Writing to Arrays
$data = [
'users' => [
['id' => 1, 'name' => 'John'],
['id' => 2, 'name' => 'Jane'],
],
];
// Update a value.
Selector::set($data, 'users[id=1:name]', 'Johnny');
// $data['users'][0]['name'] is now 'Johnny'
// Add a new property.
Selector::set($data, 'users[id=2:email]', '[email protected]');
// $data['users'][1]['email'] is now '[email protected]'
// Add a new element.
Selector::set($data, 'users[3]', ['id' => 3, 'name' => 'Bob']);
// $data['users'][3] is now ['id' => 3, 'name' => 'Bob']
// If no matching element exists, a new one is created.
Selector::set($data, 'users[id=4:name]', 'Alice');
// Adds a new element to $data['users'] with id=4 and name='Alice'
Clearing Array Elements
$data = [
'users' => [
['id' => 1, 'name' => 'John', 'email' => '[email protected]'],
['id' => 2, 'name' => 'Jane', 'email' => '[email protected]'],
],
];
// Remove a property.
Selector::clear($data, 'users[id=1:email]');
// John's email is now removed.
// Remove an entire array element.
Selector::clear($data, 'users[id=2]');
// Jane's record is now completely removed.
// Clean up empty array elements.
$data = [
'teams' => [
['id' => 1, 'members' => ['Alice', 'Bob']],
['id' => 2, 'members' => ['Charlie']],
],
];
// Remove the last member from team 2.
Selector::clear($data, 'teams[id=2:members][0]');
// Now teams[id=2:members] is an empty array.
// Derafu Selector automatically cleans up empty arrays:
// $data['teams'][1]['members'] is now an empty array.
// If we clear team 1's members too, it would clean up further.
Selector::clear($data, 'teams[id=1:members]');
// Now both teams have empty members arrays.
Working with Mixed Array Types
Selector handles both associative and indexed arrays seamlessly:
$data = [
'products' => [
'electronics' => [
['id' => 'e1', 'name' => 'Laptop', 'price' => 999],
['id' => 'e2', 'name' => 'Phone', 'price' => 699],
],
'books' => [
['id' => 'b1', 'name' => 'Novel', 'price' => 15],
['id' => 'b2', 'name' => 'Textbook', 'price' => 50],
],
],
];
// Access by category and index.
$firstElectronic = Selector::get($data, 'products.electronics[0].name');
// 'Laptop'
// Access by category and ID.
$textbookPrice = Selector::get($data, 'products.books[id=b2:price]');
// 50
// Numeric indices still work with filtering.
$secondBookName = Selector::get($data, 'products.books[1].name');
// 'Textbook'
Handling Empty or Non-existent Arrays
Selector provides safe handling for empty or non-existent arrays:
$data = [
'categories' => [
'active' => [
['id' => 1, 'name' => 'Electronics'],
['id' => 2, 'name' => 'Books'],
],
'inactive' => [],
],
];
// Access on empty array.
$inactiveCategory = Selector::get($data, 'categories.inactive[0]');
// null
// Filter on empty array.
$result = Selector::get($data, 'categories.inactive[id=1:name]');
// null
// Non-existent array path.
$result = Selector::get($data, 'categories.archived[0].name');
// null
// Providing defaults.
$result = Selector::get($data, 'categories.archived[0].name', 'Not found');
// 'Not found'
Modifying Array Elements in Place
You can modify array elements directly:
$data = [
'cart' => [
['id' => 'p1', 'name' => 'Laptop', 'quantity' => 1],
['id' => 'p2', 'name' => 'Mouse', 'quantity' => 2],
],
];
// Increase quantity.
$currentQuantity = Selector::get($data, 'cart[id=p1:quantity]');
Selector::set($data, 'cart[id=p1:quantity]', $currentQuantity + 1);
// Now p1's quantity is 2
// Add a new property to an array element.
Selector::set($data, 'cart[id=p2:price]', 25);
// Mouse now has a price property
// Modify a nested property.
$data = [
'orders' => [
[
'id' => 1,
'items' => [
['product' => 'Laptop', 'price' => 999],
],
],
],
];
// Apply discount.
Selector::set($data, 'orders[id=1:items][product=Laptop:price]', 899);
// Price is now 899
By leveraging these array handling capabilities, you can work with complex nested data structures in a clean, readable way without worrying about undefined indices or complex nesting logic.