anahkiasen/underscore-php
Underscore.php brings functional helpers to PHP inspired by Underscore.js. Chainable, collection and array utilities like map, filter, reduce, groupBy, sortBy, pluck, and more. Handy for concise data manipulation in any PHP project, including Laravel.
Installation Add the package via Composer:
composer require anahkiasen/underscore-php
No Laravel-specific setup is required—it works as a standalone library.
First Use Case
Import the library and use a basic function (e.g., map or filter):
use Underscore\Underscore;
$numbers = [1, 2, 3, 4];
$doubled = Underscore::map($numbers, function($n) { return $n * 2; });
// Result: [2, 4, 6, 8]
Where to Look First
map, filter, reduce, pluck, groupBy, and findWhere for Laravel collections.Collection Manipulation
Replace Laravel’s Collection methods with Underscore for functional programming:
$users = collect([['name' => 'John'], ['name' => 'Jane']]);
$names = Underscore::pluck($users->all(), 'name'); // ['John', 'Jane']
Data Transformation
Use map/reduce for complex transformations:
$orders = [
['id' => 1, 'items' => [10, 20]],
['id' => 2, 'items' => [15]],
];
$total = Underscore::reduce($orders, function($sum, $order) {
return $sum + array_sum($order['items']);
}, 0);
// Result: 45
Conditional Filtering
Combine with filter/where for dynamic queries:
$activeUsers = Underscore::filter($users, function($user) {
return $user['active'] && $user['role'] === 'admin';
});
Laravel Service Providers Bind Underscore globally for reusable logic:
// app/Providers/AppServiceProvider.php
public function boot() {
$this->app->singleton('underscore', function() {
return new Underscore\Underscore();
});
}
Then inject via constructor:
public function __construct(private Underscore\Underscore $underscore) {}
map to transform Eloquent models to JSON:
$data = Underscore::map($posts->toArray(), function($post) {
return ['id' => $post['id'], 'title' => $post['title']];
});
filter/reject:
$cleanData = Underscore::pick($request->all(), ['name', 'email']);
isEqual, isEmpty, etc.groupBy with nested keys).@php
$grouped = Underscore::groupBy($items, function($item) {
return $item['category'];
});
@endphp
each/forEach.Archived Package
reduce or pluck).Laravel Collection Conflicts
Collection methods on the same array:
// ❌ Risky: Underscore modifies the array in-place.
$collection = collect([1, 2, 3]);
Underscore::map($collection->all(), ...); // Mutates original!
Underscore::map(clone $collection->all(), ...);
Callback Scope
$this as the array item (like Underscore.js), which may break in Laravel’s context:
// ❌ Unexpected $this binding
Underscore::map($users, function() { return $this->name; });
Underscore::map($users, fn($user) => $user['name']);
Performance
reduce/map are slower than Laravel’s Collection for large datasets.Underscore::inspect() to log complex objects:
dd(Underscore::inspect($data));
pluck fails on non-associative arrays).try-catch for silent failures:
try {
$result = Underscore::filter($data, $callback);
} catch (\Error $e) {
$result = [];
}
config/underscore.php exists.class CustomUnderscore extends Underscore\Underscore {
public static function snakeCaseKeys(array $array) {
return Underscore::map($array, function($item) {
return is_array($item)
? self::snakeCaseKeys($item)
: $item;
}, 'keys');
}
}
Add Custom Functions Override or extend the base class:
Underscore\Underscore::mixin([
'chunk' => function(array $array, $size) {
// Custom implementation
}
]);
Laravel Facade Create a facade for cleaner syntax:
// app/UnderscoreFacade.php
class UnderscoreFacade extends \Illuminate\Support\Facades\Facade {
protected static function getFacadeAccessor() {
return 'underscore';
}
}
Register in config/app.php:
'aliases' => [
'Underscore' => App\Facades\UnderscoreFacade::class,
],
Usage:
$result = Underscore::chunk($data, 2);
Integration with Laravel Mix Bundle Underscore for frontend-backend consistency (if using PHP for JS-like logic).
How can I help you explore Laravel packages today?