Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Values Laravel Package

formapro/values

A lightweight Laravel/PHP package for working with typed values and value objects. It provides a clean, expressive API to encapsulate data, validate inputs, and keep domain logic consistent, reusable, and easy to maintain without unnecessary boilerplate.

Deep Wiki
Context7

Getting Started

Install

composer require formapro/values

Before adopting, open vendor/formapro/values/composer.json and check the PHP constraint. The last tagged release is from March 2019, so it predates PHP 8. Verify it runs cleanly on your runtime (see Gotchas) before wiring it into anything long-lived.

Where to look first

  • src/Value.php — the whole library, essentially. Read it end to end; it is small.
  • src/ValueInterface.php — the contract you should type-hint against in your own code.
  • src/functions.php (if present) — the value() shorthand helper.
  • tests/ — the fastest way to learn the exact dot-notation semantics (get, set, has, remove, defaults, merge, toArray) without guessing.

First use case

Wrap an incoming payload — a config array, an API response body, a queue message — and access it with dot notation instead of a chain of isset() and ??:

use Formapro\Values\Value;

$payload = Value::create([
    'user' => [
        'name'  => 'Alice',
        'roles' => ['admin', 'editor'],
    ],
    'meta' => ['trace_id' => 'abc123'],
]);

$payload->get('user.name');            // 'Alice'
$payload->get('user.roles');           // ['admin', 'editor']
$payload['meta.trace_id'];             // ArrayAccess works too
$payload->set('user.email', '[email protected]');  // creates intermediate keys
$payload->has('user.email');           // true
$payload->toArray();                   // back to a plain array

That is the sweet spot: a single, boring, array-backed object that behaves like both an array and an object, so you stop threading null-checks through your code.

Implementation Patterns

Boundary adapter. Treat Value as a transport object at the edges of your app, not as a domain model. Convert once on the way in, convert once on the way out:

$value = Value::create($request->all());   // in
// ... read fields with dot notation ...
$model->fill($value->only(...));           // or ->toArray() at the boundary

Keeping the conversion at the boundary means your domain entities stay typed and the Value never leaks into business logic.

Config with defaults. defaults() only fills keys that are absent, which is exactly the "merge user config over package defaults" problem:

$config = Value::create($userConfig)->defaults([
    'cache.driver' => 'redis',
    'cache.ttl'    => 3600,
]);

This is safer than array_merge because it respects nesting via dot keys and will not clobber a caller's explicit null.

Wrapping domain objects instead of duplicating them. Subclass Value (or compose it) when you want named accessors on a known shape while keeping array access for generic code:

class StripeWebhook extends Value
{
    public function isRefund(): bool
    {
        return $this->get('type') === 'charge.refunded';
    }
}

You get $webhook['type'], $webhook->isRefund(), json_encode($webhook), and count($webhook) for free.

Queue / message payloads. The library came out of the Forma-Pro ecosystem and fits message-driven code well: the producer builds a Value, the consumer receives an array and rehydrates a Value. Because it implements JsonSerializable, you can hand it straight to a JSON encoder when dispatching.

Framework glue. Nothing here is framework-specific — no service provider is required.

  • Laravel: resolve in a form request or a middleware and pass the Value down, or construct it inline in a controller. Use Value::create() rather than the package's value() helper (see Gotchas).
  • Symfony: type-hint ValueInterface in services that need arbitrary option bags; build it from $request->request->all() or a decoded YAML config.

Testing. Assert against toArray() for whole-structure comparisons and against get() for single fields. Because toArray() returns plain arrays, assertEquals/assertSame with your fixtures works without custom matchers.

Gotchas and Tips

The value() helper collides with Laravel. Laravel ships a global value() helper in illuminate/support. If you use function Formapro\Values\value; in a file, your local import wins there — but anywhere else in the app the two silently diverge. Standardise on Value::create() and avoid the ambiguity entirely.

It is mutable. Despite the "alter ego object" framing, set()/remove()/offsetSet mutate the instance. Pass a Value around and any collaborator can change it. If you need immutability, clone at boundaries or wrap it behind a read-only interface.

Indirect modification of nested elements does not work.

$value['user']['name'] = 'Bob';       // no effect / notice
$value->get('user')['name'] = 'Bob';  // no effect (arrays are returned by value)

Always write through the API: $value->set('user.name', 'Bob'). This is the single most common mistake with this kind of wrapper.

Missing keys return null, silently. A typo in 'user.email' vs 'user.emails' looks identical to an intentionally absent field. Use has() for required-field checks, and validate the shape once at the boundary rather than scattering has() calls everywhere.

isset() is not has(). isset($value['a.b']) routes through offsetExists, which — like native PHP — reports false when the key exists with a null value. If null is a meaningful value in your payload, isset() will lie to you.

Keys containing literal dots are unreachable by dot notation. ['foo.bar' => 1] will be interpreted as nesting. If upstream data can have dotted keys, escape them, rename them at the boundary, or fall back to toArray().

Numeric keys and lists. Dot paths through list indices work, but don't rely on the wrapper for list manipulation — there are no map, filter, reduce, or pluck methods. Call toArray() and use native array functions; that is the intended escape hatch.

PHP 8.1+ deprecation noise. Classes implementing ArrayAccess, IteratorAggregate, Countable, or JsonSerializable without return types emit #[\ReturnTypeWillChange] deprecations on PHP 8.1+, and Serializable is deprecated outright. If the package is noisy on your runtime, the pragmatic fix is a thin subclass in your own namespace that redeclares the interface methods with proper return types, or a fork pinned in repositories. Budget for this — with a 2019 release, no upstream fix is coming.

toArray() is a deep conversion; object identity is lost. Anything you stashed via set() that is a Value gets flattened. Conversely, non-Value objects are left as-is, so json_encode($value) may serialize differently than json_encode($value->toArray()) if you mixed in DTOs. Keep the contents array-shaped.

Debugging. var_dump($value) shows the private storage and nested Value objects, not the shape you care about. print_r($value->toArray()) or json_encode($value, JSON_PRETTY_PRINT) is far quicker. When a get() returns null, print the full path chain (->keys()) to see whether the nesting is what you assumed.

Performance in hot loops. Every dotted access walks the array segment by segment. It is cheap, but if you are reading the same path tens of thousands of times, hoist it into a local variable or extract the sub-structure once with get().

Extension point summary. Subclass Value for named accessors; implement ValueInterface if you need a different backing store while keeping call sites identical; use toArray() as the universal adapter back to plain PHP. There is nothing else to extend — the surface is deliberately small, which is the main reason to pick it over a full collection library.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package