mathiasgrimm/arraypath
Convenient array manipulation for PHP, especially multidimensional arrays. Safely get, set, check existence, add or remove values using simple “a/b/c” paths, avoiding undefined index notices. Optional class alias (A) for cleaner calls and IDE autocomplete.
Installation:
Add to composer.json:
"require": {
"mathiasgrimm/arraypath": "^2.0"
}
Run composer update.
Register Class Alias (recommended for IDE autocompletion):
In AppServiceProvider.php (or any bootstrap file):
use MathiasGrimm\ArrayPath\ArrayPath;
public function boot()
{
ArrayPath::registerClassAlias('A');
}
First Use Case:
Replace a nested isset() check with A::get():
// Before
$name = isset($user['profile']['first_name']) ? $user['profile']['first_name'] : null;
// After
$name = A::get($user, 'profile/first_name');
Data Retrieval:
$value = A::get($array, 'path/to/value');
$value = A::get($array, 'path/to/value', 'default');
$city = A::get($request->all(), 'user.address.city');
Data Manipulation:
A::set($array, 'user.profile.email', 'user@example.com');
$removedValue = A::remove($array, 'user.profile.email');
Existence Checks:
array_key_exists() chains:
if (A::exists($config, 'app.settings.featureFlags')) {
// Safe to proceed
}
Dynamic Paths (e.g., from user input):
$path = $request->input('dynamic_path');
$value = A::get($data, $path);
Laravel Config:
Replace config('app.settings.nested.key') with:
$value = A::get(config('app.settings'), 'nested.key');
Form Requests:
Use in prepareForValidation() to flatten nested arrays:
$this->merge([
'user_name' => A::get($this->all(), 'user/name'),
]);
API Responses: Sanitize nested data before returning:
$response['user'] = A::get($data, 'user', []);
Testing: Assert array paths in PHPUnit:
$this->assertEquals('John', A::get($user, 'profile/first_name'));
Custom Separators (e.g., for JSON-like paths):
ArrayPath::setSeparator('.');
$value = A::get($data, 'user.profile.name');
Path Validation:
Combine with A::exists() to validate required fields:
if (!A::exists($request->all(), 'user.email')) {
throw new \InvalidArgumentException('Email is required.');
}
Deep Merging:
Use A::set() to merge nested arrays:
$defaults = ['user' => ['role' => 'guest']];
A::set($defaults, 'user.role', 'admin'); // Override
Empty Arrays:
A::set() on an empty array may not create intermediate keys as expected (fixed in v2.0.7, but test edge cases).$array = ['user' => []];
A::set($array, 'user/profile', ['name' => 'John']);
Non-String Keys:
0/1/2) may behave unexpectedly.A::get($array, (string) $dynamicKey);
Default Values:
A::get() returns null for missing paths (not false or empty string).if (A::get($data, 'path')) { // Always false if path doesn’t exist!
A::exists() or provide a default:
if (A::exists($data, 'path')) { ... }
// or
$value = A::get($data, 'path', '');
Class Alias Scope:
A) is static and global. Avoid naming conflicts in large teams.App\A) to scope it:
ArrayPath::registerClassAlias('App\A');
Performance:
Path Errors:
A::get() silently returns null for invalid paths. Use A::exists() to debug:
if (!A::exists($data, 'user.profile')) {
dd($data); // Inspect structure
}
Circular References:
get_debug_type() to detect:
if (is_array($data) && get_debug_type($data) === 'array') {
// Safe to use ArrayPath
}
IDE Issues:
A:: if the alias isn’t registered early.bootstrap/app.php).Custom Logic:
MathiasGrimm\ArrayPath\ArrayPath:
class CustomArrayPath extends ArrayPath {
public static function customGet($array, $path) {
// Add logic here
return parent::get($array, $path);
}
}
Path Sanitization:
$path = urldecode($request->input('path'));
$value = A::get($data, $path);
Integration with Laravel:
$this->app->singleton('arrayPath', function () {
return new ArrayPath();
});
Separator Persistence:
ArrayPath::setSeparator('/'); // Default
Case Sensitivity:
user/Name ≠ user/name).$normalizedPath = strtolower($path);
Non-Associative Arrays:
0/1/2 work but may not behave as expected for numeric keys.A::set($array, 'items/0/name', 'Item 1');
Request Data:
Request objects by casting to array:
$value = A::get($request->all(), 'user.name');
Validation:
$validator = Validator::make($request->all(), [
'user.name' => 'required|string',
]);
// Or dynamically:
$path = 'user.'.$request->input('field');
$validator->sometimes($path, 'required', function () {
return A::exists($request->all(), 'user');
});
Service Providers:
boot() to ensure it’s available early:
public function boot()
{
ArrayPath::registerClassAlias('A');
}
Testing:
A:: calls in tests:
A::shouldReceive('get')->with($data, 'path')->andReturn('mocked');
How can I help you explore Laravel packages today?