Collection::toJson

Serializes the collection to a JSON string, with optional json_encode flags.

Signature
public function toJson(int $options = 0): string

Parameters

ParameterTypeDescription
$optionsoptionalint= 0A bitmask of json_encode flags, for example JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES.

Return value

stringThe JSON representation of the collection. Returns the string "false" is never produced, but json_encode returns boolean false on failure, which is then cast to an empty string by the string return type.

Errors

Does not throw by default; pass JSON_THROW_ON_ERROR to turn encoding failures such as malformed UTF-8 or recursion into a JsonException instead of a silent failure.

toJson calls jsonSerialize() and passes the result to json_encode with the flags you supply. jsonSerialize() unwraps each item that implements JsonSerializable, Jsonable or Arrayable, which is why models and nested collections come out expanded rather than as {}.

The array-versus-object trap

This is the reason most people land on this page. json_encode emits a JSON array only when the PHP array's keys are exactly 0..n-1 in order. Every key-preserving collection method — filter, where, reject, sortBy, unique, a negative take — can leave gaps, and the moment there is a gap the output becomes an object keyed by the surviving indexes. The fix is always values() immediately before serializing.

What trips people up

Flags are a bitmask, not a boolean: combine them with |. Encoding failures are silent by default — invalid UTF-8 or a recursive structure makes json_encode return false, so pass JSON_THROW_ON_ERROR when the data is untrusted.

Also, returning a collection directly from a controller already JSON-encodes it, so calling toJson() yourself there produces a double-encoded string.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Store a small structured payload in a database text column
  • Write a deterministic fixture file for a test
  • Log a structured context object as a single JSON line
  • Build a JSON string for a client that cannot accept an object where it expects an array

Frequently asked questions

Why does my Laravel collection encode as a JSON object instead of an array?

Because its keys are no longer 0..n-1 in order, which is the only case json_encode renders as an array. Methods like filter, where, reject, sortBy and a negative take preserve the source keys, so chain ->values() before toJson().

How do I pretty print a collection as JSON?

Pass the flag: $collection->toJson(JSON_PRETTY_PRINT). Options is a json_encode bitmask, so combine several with the pipe operator, as in JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES.

Why is toJson() returning an empty string?

json_encode failed and returned false, which the string return type turns into an empty string — usually malformed UTF-8 or a recursive structure. Pass JSON_THROW_ON_ERROR to get a JsonException with the real reason.

More examples

Which methods leave gaps in the keys

filter, reject, sort and a negative take all keep the source keys, and each one produces a JSON object. sort() is the sneakiest: the keys are all still present, just reordered, and json_encode requires 0..n-1 in order. Only map, which never disturbs the key sequence, survives untouched.

Example · php
<?php

$n = collect([5, 3, 9, 1, 7]);

echo $n->filter(fn ($v) => $v > 4)->toJson(), "\n";
echo $n->reject(fn ($v) => $v > 4)->toJson(), "\n";
echo $n->sort()->toJson(), "\n";
echo $n->take(-2)->toJson(), "\n";

// map() maps keys through unchanged, so it stays an array:
echo $n->map(fn ($v) => $v * 2)->toJson(), "\n";

// Output:
// {"0":5,"2":9,"4":7}
// {"1":3,"3":1}
// {"3":1,"1":3,"0":5,"4":7,"2":9}
// {"3":1,"4":7}
// [2,6,18,2,14]

Flags and safe encoding

The flags argument is passed straight to json_encode, so combine flags with the bitwise OR operator. The third call shows the default failure mode: json_encode returns false on the latin-1 byte, and the string return type turns that into an empty string with no warning. JSON_THROW_ON_ERROR converts it into a JsonException you can actually catch.

Example · php
<?php

$link = collect([
    'title' => 'Prix fixé',
    'url'   => 'https://example.test/a/b',
]);

echo $link->toJson(), "\n";
echo $link->toJson(JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE), "\n";

// Invalid UTF-8 fails silently by default.
$bad = collect(['name' => "caf\xE9"]);
var_dump($bad->toJson());

try {
    $bad->toJson(JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
    echo $e->getMessage(), "\n";
}

// Output:
// {"title":"Prix fixé","url":"https:\/\/example.test\/a\/b"}
// {"title":"Prix fixé","url":"https://example.test/a/b"}
// string(0) ""
// Malformed UTF-8 characters, possibly incorrectly encoded

Do not double-encode in a controller

A collection returned from a controller is already converted to a JSON response by the framework, so calling toJson() yourself yields a quoted, escaped string. The values() call is still required: filter() preserved the model keys, and without it the response body is an object keyed by position. Needs a booted application with a database.

Example · php
<?php

namespace App\Http\Controllers;

use App\Models\Product;

class ProductController extends Controller
{
    public function index()
    {
        $products = Product::where('active', true)->get();

        // Wrong: the response is a JSON string containing JSON.
        // return $products->filter(fn ($p) => $p->inStock())->toJson();

        // Right: return the collection and let the framework encode it,
        // but reindex first or filter() leaves you a JSON object.
        return $products->filter(fn ($p) => $p->inStock())->values();
    }
}

Discussion

  • Be the first to comment on this lesson.