Anvil
Anvil - The mobile companion for Laravel Forge. Available now. Download for iOS

Mastering Laravel’s data_get(): Read Anything from Arrays, Objects, and Collections

If you’ve ever written a long chain of null checks to fetch a deeply nested value — foo['bar']['baz'] ?? null — you’ll love Laravel’s data_get() helper. It’s a tiny, dependable utility that safely retrieves values from arrays, objects, ArrayAccess implementations, and even nested structures using a simple “dot notation.”

6 min read - 8,700 views -

In this guide, you’ll learn every practical way to use data_get(): from the basics to advanced wildcard patterns, defaults, edge cases, and how it compares to alternatives like Arr::get() and the PHP nullsafe operator.

  • What is data_get()
  • Basic usage (dot notation, arrays, objects, collections)
  • Providing default values (including closures)
  • Wildcards with * and deep matching
  • Escaping dots in keys
  • Using data_get() with Collections
  • Comparing data_get() vs Arr::get() vs nullsafe operator
  • Common patterns and real-world examples
  • Edge cases and gotchas
  • Related helpers: data_set() and data_fill()

What is data_get()

Signature:

  • mixed data_get(mixed $target, string|array|null $key, mixed $default = null)

  • $target: The thing you’re reading from — array, object, ArrayAccess, or a mix.

  • $key: A dot-notated path, an array of segments, or null (which returns the whole target).

  • $default: Value to return if the path isn’t found. Can be a value or a closure.

Under the hood, data_get() walks your structure segment by segment. For objects, it reads public properties (and properties via magic __get). For arrays, it reads array keys. If at any point a segment doesn’t exist, it returns the default value.

Basic usage

Arrays

1$user = [
2 'name' => 'Taylor',
3 'contacts' => [
4 'email' => '[email protected]',
5 'social' => [
6 'twitter' => '@taylorotwell',
7 ],
8 ],
9];
10 
11data_get($user, 'contacts.email'); // '[email protected]'
12data_get($user, 'contacts.social.twitter'); // '@taylorotwell'

Objects

1class Profile {
2 public string $timezone = 'UTC';
3}
4 
5class User {
6 public Profile $profile;
7 public function __construct()
8 {
9 $this->profile = new Profile;
10 }
11}
12 
13$user = new User;
14 
15data_get($user, 'profile.timezone'); // 'UTC'

If your object implements ArrayAccess or uses magic getters, data_get() can still read the value.

Mixed arrays and objects

1$post = (object) [
2 'author' => [
3 'name' => 'Sam',
4 'links' => (object) ['website' => 'https://example.com'],
5 ],
6];
7 
8// data_get() happily traverses both arrays and objects.
9data_get($post, 'author.links.website'); // 'https://example.com'

When $key is null

1$data = ['a' => 1];
2data_get($data, null); // returns the entire $data value

Providing default values

If any segment along the path is missing, data_get() returns the default (third argument).

1data_get($user, 'contacts.phone', 'n/a'); // 'n/a'

You can compute the default lazily using a closure. Laravel will call the closure only if the value is missing:

1$data_get_default = data_get($user, 'contacts.sms', fn () => config('defaults.sms_number'));

This is helpful when the default is expensive to compute or you need environment configuration.

Wildcards with *

Wildcards let you fetch values from lists in one shot. A * segment means “for each element at this level, continue the lookup and return the results.”

One-level wildcard

1$users = [
2 ['name' => 'Ada', 'email' => '[email protected]'],
3 ['name' => 'Linus', 'email' => '[email protected]'],
4];
5 
6data_get($users, '*.email');

Deep wildcards

1$teams = [
2 ['name' => 'Alpha', 'members' => [['name' => 'A1'], ['name' => 'A2']]],
3 ['name' => 'Beta', 'members' => [['name' => 'B1']]],
4];
5 
6data_get($teams, '*.members.*.name');
7// [['A1', 'A2'], ['B1']]

Note: The shape of the returned value mirrors the wildcard levels. If you want a flat list, you can flatten after:

1collect(data_get($teams, '*.members.*.name'))->flatten()->all();
2// ['A1', 'A2', 'B1']

Wildcards with missing keys

If a key is missing in some items, those branches produce null (and may be omitted if subsequent traversal fails):

1$users = [
2 ['name' => 'Ada', 'contacts' => ['email' => '[email protected]']],
3 ['name' => 'Linus'],
4];
5 
6data_get($users, '*.contacts.email');
7// ['[email protected]', null]

Default values with wildcards

The default applies when the top-level traversal can’t find anything. For missing values within a wildcard branch, you’ll typically normalize after:

1$result = data_get($users, '*.contacts.phone');
2// [null, null]
3 
4$normalized = collect($result)->map(fn ($value) => $value ?? 'n/a')->all();
5// ['n/a', 'n/a']

Escaping dots in keys

If your array key literally contains a dot, escape it with a backslash (.).

1$settings = [
2 'cache' => [
3 'driver.name' => 'redis',
4 ],
5];
6 
7data_get($settings, 'cache.driver\.name'); // 'redis'

If your key string is already segmented, you can also pass an array of segments instead of a dot string:

1data_get($settings, ['cache', 'driver.name']); // equivalent

Using data_get() with Collections

Collections are iterable, but data_get() expects arrays/objects for traversal. The simplest approach is to call ->all() on the collection when it represents a list. For object-like collections (e.g., keyed by strings), data_get() works with the underlying array.

1$users = collect([
2 ['name' => 'Ada', 'email' => '[email protected]'],
3 ['name' => 'Linus', 'email' => '[email protected]'],
4]);
5 
6data_get($users->all(), '*.email');

For nested collections, convert the relevant layers with ->all() as needed, or map with data_get() per item:

1$teams = collect([
2 ['members' => collect([['name' => 'A1'], ['name' => 'A2']])],
3]);
4 
5$names = $teams->map(fn ($team) => data_get($team, 'members.*.name'));
6// $names: collect([['A1', 'A2']])

data_get() vs Arr::get() vs PHP’s nullsafe operator

  • data_get()

    • Works with arrays, objects, ArrayAccess, and mixes of these.
    • Supports wildcards (*), escaped dots, and closure defaults.
    • Great for traversing heterogeneous data (API responses, decoded JSON, Eloquent models, DTOs).
  • Arr::get()

    • Focused on arrays/ArrayAccess. No wildcard expansion.
    • If you only work with arrays and want a slightly smaller surface area, Arr::get() is fine.
  • PHP nullsafe operator (->?)

    • Reads object properties/methods, but doesn’t handle arrays or wildcards.
    • Great for straight object graphs; less helpful for mixed array/object structures.

Often, data_get() replaces nested null coalescing and complex conditionals in one readable call.

Common patterns and real-world examples

Reading API responses

1$response = Http::get('https://api.example.com/user')->json();
2 
3$name = data_get($response, 'profile.name');
4$firstPostTitle = data_get($response, 'posts.0.title');
5$allTagNames = collect(data_get($response, 'posts.*.tags.*.name'))->flatten()->all();

Reading Eloquent models safely

1// Given $order is an Eloquent model with nested relations
2$city = data_get($order, 'shippingAddress.city', 'Unknown');
3$lineItemsSkus = data_get($order, 'items.*.sku', []);

Transforming data for views

1$payload = [
2 'users' => [
3 ['name' => 'Ada', 'roles' => [['name' => 'admin'], ['name' => 'editor']]],
4 ['name' => 'Linus', 'roles' => [['name' => 'viewer']]],
5 ],
6];
7 
8$userRoles = collect(data_get($payload, 'users.*.roles.*.name'))
9 ->map(fn ($roles) => collect($roles)->sort()->values()->all())
10 ->all();
11// $userRoles => [['admin','editor'], ['viewer']]

Guards for optional config

1$dsn = data_get(config('services.sentry'), 'dsn');
2$retries = data_get(config('queue.connections.redis'), 'retry_after', 90);

Edge cases and gotchas

  • Non-existent intermediate segments short-circuit to default.
    • Example: data_get($user, 'profile.timezone', 'UTC') returns 'UTC' if profile is null or missing.
  • Wildcards preserve structure depth.
    • Use Collection::flatten() (or array flattening) if you need a single list.
  • Numeric indices are valid segments.
    • data_get($posts, '0.title') fetches the first item’s title.
  • Don’t confuse property access with method calls.
    • data_get() does not execute methods; it reads properties/ArrayAccess.
  • Escaping matters for literal dots in keys.
    • Use driver.name or pass segments as an array.

Related helpers: data_set() and data_fill()

While data_get() reads values, its siblings write values into nested structures.

  • data_set(&$target, $key, $value, $overwrite = true)
    • Sets a value at the given path, creating intermediate arrays/objects as needed.
    • Respects the overwrite flag.
  • data_fill(&$target, $key, $value)
    • Like data_set() but only sets the value if it is missing.

Example:

1$user = [];
2 
3data_set($user, 'profile.timezone', 'UTC');
4// $user = ['profile' => ['timezone' => 'UTC']]
5 
6$data = [];
7data_fill($data, 'a.b', 123);
8// $data = ['a' => ['b' => 123]]

Final tips

  • Prefer data_get() when input shape is uncertain (API, untrusted payloads, optional relations).
  • Use closure defaults for lazy or environment-based fallbacks.
  • Combine wildcards with Collections for powerful transformations.
  • Escape keys with dots using \. or supply key segments as an array.

With data_get(), your code becomes safer and more expressive, reducing the need for repetitive null checks and nested conditionals.

Read next

Uncommon HTML Elements You’ll Actually Use: A Practical Guide

Modern HTML includes a bunch of small but powerful elements that improve semantics, accessibility, and UX without heavy JavaScript. In this guide, we’ll explore lesser‑used tags you can add to your toolkit today. We’ll focus on what they’re for, how to use them accessibly, and common pitfalls. Examples are intentionally minimal so you can copy-paste and adapt.

8 min read - 5,731 views -

Authentication Log v6.0.0

We're excited to announce the release of Laravel Authentication Log v6.0.0! This major release brings significant improvements to security, user experience, and developer productivity. With support for Laravel 11.x and 12.x, enhanced suspicious activity detection, comprehensive session management, and numerous bug fixes, this release represents a substantial step forward for the package.

7 min read - 4,297 views -