bfg/object
A lightweight Laravel/PHP package for object utilities, offering simple helpers to create, inspect, and manipulate object data in a clean, consistent way. Easy to drop into existing projects and use alongside Laravel or standalone PHP code.
Install the package via Composer:
composer require bfg/object
In a Laravel app the service provider is auto-discovered; if you are on an older Laravel version or a non-Laravel project, register Bfg\Object\ObjectServiceProvider manually in config/app.php. Check the README first for whether a config file is publishable:
php artisan vendor:publish --provider="Bfg\Object\ObjectServiceProvider"
Then look at the package's src/ directory — for a utility package this small, the public API is almost certainly a single static helper class plus one or two traits. Read that class top to bottom before anything else; it is the whole package.
The first real use case is turning loosely-typed data (request payloads, Eloquent toArray() output, decoded JSON) into something you can read and write fluently and safely:
use Bfg\Object\Object; // confirm exact namespace/class in src
$obj = Object::make(['user' => ['name' => 'Ada', 'roles' => ['admin']]]);
$obj->get('user.name'); // "Ada"
$obj->get('user.roles.0'); // "admin"
$obj->get('user.missing', null); // fallback
If that matches your expectations, the package is a lightweight alternative to data_get()/data_set() with an object wrapper. If the API differs, adapt the examples below — the patterns hold.
Dot-notation access as a safe reader. The highest-value day-to-day use is reading deeply nested optional data without a chain of isset() checks. Wrap request data or API responses once at the boundary and pass the wrapper around instead of raw arrays:
$payload = Object::make($request->all());
$email = $payload->get('contact.email');
$tags = $payload->get('meta.tags', []);
Hydrating DTOs from arrays. If the package exposes a toObject()/hydrate() style conversion, use it to turn an array into a stdClass-like structure for read-only consumption, then convert back with toArray() before persisting or serializing:
$dto = Object::make($model->toArray());
$dto->set('settings.theme', 'dark');
$model->update($dto->toArray());
Custom Eloquent cast. The most Laravel-native integration is a cast that stores JSON but exposes an object wrapper on the model:
protected $casts = [
'settings' => \Bfg\Object\Casts\ObjectCast::class, // verify class name
];
If no cast ships with the package, write a small one yourself that calls Object::make() in get() and ->toArray() in set(). This keeps the object API available everywhere without leaking array handling into controllers.
Response shaping. Use the wrapper to build API resources where fields are optional and nested. Reading via dot notation with defaults keeps controllers free of null-coalescing noise, and toArray() feeds response()->json() cleanly.
Config and settings manipulation. For runtime config overrides or per-tenant settings stored as nested arrays, set('a.b.c', $value) with dot notation is more readable than manual nested array assignment, and it avoids the classic "undefined index" dance.
Wrap, don't scatter. Pick one boundary (request → service, or DB → presenter) where you convert to the object, and convert back to arrays before crossing back out. This keeps the rest of the codebase free of a dependency on a low-traffic package.
composer.json, and isolate usage behind your own thin wrapper class so you can swap it for data_get()/data_set() or Illuminate\Support\Collection if the package goes unmaintained. The whole thing is replaceable in an afternoon.'user.name' as a literal key). If you ingest arbitrary third-party payloads, sanitize keys or fall back to direct array access for those cases.stdClass internally, which silently loses numeric-keyed arrays or turns them into objects. Round-trip a nested structure through toArray() in a test before trusting it in production.isset. If the wrapper implements __get/__isset, isset($obj->foo) can behave differently from $obj->get('foo') !== null. Prefer the explicit get()/has() methods; they are easier to reason about and to grep.set() mutates in place or returns a clone. If it returns a new instance, forgetting to reassign is a common bug: $obj = $obj->set(...).JsonSerializable and ArrayAccess if you plan to pass it into response()->json() or Blade. Otherwise you get an empty {} or a __PHP_Incomplete_Class surprise."0" → 0, "false" → false) during hydration. That is convenient until it silently changes an ID or a flag. Test a few representative values.data_get()/collections there. Reserve the wrapper for small, nested, human-authored structures (config, payloads, settings).dd()/dump() on a magic wrapper can be misleading; cast with (array) $obj or call ->toArray() before dumping. Add a dump($obj->toArray()) in your first integration test to confirm the internal shape.data_get()/data_set() suffice. For most Laravel codebases the framework helpers cover the same ground. Adopt this package only where its object wrapper genuinely improves readability (fluent chaining, DTOs, settings), not as a blanket replacement for array access.How can I help you explore Laravel packages today?