windwalker/data
Windwalker Data is a lightweight PHP data container and toolkit for managing arrays and objects with convenient accessors and helpers. Part of the Windwalker 4 ecosystem. Install via Composer and see the docs for usage and APIs.
Installation:
composer require windwalker/data ^4.0
Ensure your Laravel project meets the package's PHP version requirements (typically 8.0+).
First Use Case:
Import the core Data class and initialize a basic data container:
use Windwalker\Data\Data;
$data = new Data(['name' => 'John', 'age' => 30]);
echo $data->get('name'); // Output: John
Where to Look First:
src/Data.php for core functionality and method signatures.tests/ directory for usage patterns and edge cases.Data Container:
Use Data as a lightweight alternative to arrays or stdClass for structured data:
$user = new Data([
'id' => 1,
'roles' => ['admin', 'user'],
'metadata' => new Data(['created_at' => now()])
]);
Nested Access: Chain dot notation for nested properties:
$user->get('metadata.created_at'); // Access nested data
$user->set('metadata.updated_at', now()); // Set nested data
Magic Methods:
Leverage __get()/__set() for dynamic property access:
$user->name = 'Jane'; // Equivalent to $user->set('name', 'Jane')
Array Conversion:
Use toArray() for seamless integration with Laravel's collection methods or APIs:
$array = $user->toArray();
$collection = collect($array)->filter(fn($v) => $v !== null);
Validation Integration:
Combine with Laravel's Validator for form/data validation:
use Illuminate\Support\Facades\Validator;
$validator = Validator::make($user->toArray(), [
'name' => 'required|string|max:255',
'age' => 'integer|min:18'
]);
Service Container Binding:
Bind Data to Laravel's container for dependency injection:
$this->app->bind(Data::class, fn() => new Data());
Eloquent Models:
Use Data to transform model attributes before returning:
public function toResponseArray()
{
return (new Data($this->attributes))->only(['id', 'name'])->toArray();
}
API Resources:
Extend Data in custom resources for consistent response formatting:
class UserResource extends Data
{
public function __construct($resource)
{
parent::__construct($resource);
$this->append('full_name', $this->get('first_name') . ' ' . $this->get('last_name'));
}
}
Form Requests:
Validate and transform request data using Data:
public function rules()
{
return [
'user.*' => ['array'],
'user.*.name' => ['string']
];
}
public function prepareForValidation()
{
$this->merge([
'user' => new Data($this->user)->toArray()
]);
}
Nested Data Mutability:
Nested Data objects are not automatically cloned when using set(). Modify with caution:
$user->set('metadata', new Data(['key' => 'value'])); // Overwrites existing metadata
Circular References:
Avoid circular references in Data objects (e.g., $user->set('self', $user)), as they can cause infinite loops in toArray() or serialization.
Type Safety:
The package does not enforce type hints. Validate types manually or use Laravel's Validator:
if (!is_int($user->get('age'))) {
throw new \InvalidArgumentException('Age must be an integer.');
}
Magic Methods Overhead:
Dynamic property access ($data->property) triggers __get()/__set(), which may impact performance in tight loops. Use explicit methods (get(), set()) for critical paths.
Serialization Quirks:
Data objects are not JSON-serializable by default. Use toArray() or implement JsonSerializable:
$data->jsonSerialize(); // Requires custom implementation
Inspect Structure:
Use dump() to visualize the Data object hierarchy:
\Illuminate\Support\Facades\Log::debug((new Data($data))->toArray());
Check for Overwrites: Debug nested property issues with:
$data->has('path.to.property'); // Verify existence before setting
Validator Errors:
If validation fails, inspect the raw Data object:
$validator = Validator::make($data->toArray(), $rules);
if ($validator->fails()) {
dd($data->toArray(), $validator->errors());
}
Default Values:
Use get() with a default value to avoid null checks:
$name = $data->get('name', 'Anonymous'); // Returns 'Anonymous' if 'name' is missing
Immutable Data:
Create read-only instances by overriding set():
class ReadOnlyData extends Data
{
public function set($key, $value = null)
{
throw new \RuntimeException('Read-only data cannot be modified.');
}
}
Extension Points:
Extend Data to add custom methods or logic:
class ExtendedData extends Data
{
public function isAdult()
{
return $this->get('age', 0) >= 18;
}
}
Performance:
For large datasets, prefer toArray() over chained get() calls to minimize method overhead:
// Less efficient:
$data->get('a')->get('b')->get('c');
// More efficient:
$array = $data->toArray();
$array['a']['b']['c'];
Testing:
Use Data::make() in tests for consistent fixtures:
$user = Data::make(['name' => 'Test', 'active' => true]);
$this->assertTrue($user->get('active'));
How can I help you explore Laravel packages today?