Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

BillRiess's avatar

Filter method on Collections results in unexpected output

When using the filter method on collections I am seeing mixed results. It seems that if the filter returns all the items in a collection then it returns the values of the collection without keys. If anything is filtered then it returns key/value pairs.

Filter returns everything:

$collection = collect([
  0 => "a",
  1 => "b",
  2 => null,
  3 => "4"
]);

$collection->filter(function($item) {
    return $item !== "Hello, World!";
});

Notice how the output has no keys:

Illuminate\Support\Collection {#973
     all: [
       "a",
       "b",
       null,
       "4",
     ],
   }

Now let's filter with some results:

$collection = collect([
  0 => "a",
  1 => "b",
  2 => null,
  3 => "4"
]);

$collection->filter(function($item) {
    return is_numeric($item);
});

Notice the output has keys:

Illuminate\Support\Collection {#973
     all: [
       3 => "4",
     ],
   }
0 likes
5 replies
tykus's avatar
tykus
Best Answer
Level 104

Whenever you filter a Collection, the items are not re-keyed so you will have potentially non-zero indexed, non-contiguous indexes - whenever this happens, the keys will be visible; otherwise they will not. You can standardise the behaviour by re-keying the array using the values method, e.g.

$collection->filter(function($item) {
    return is_numeric($item);
})->values();
2 likes
natepisarski's avatar

I actually wound up getting to the bottom of this one with your help. It all comes down to an implementation detail in PHP arrays.

Basically, when items are filtered you wind up with gaps in your numeric indexes.

[0 => 'Kentucky', 3 => 'Fried', 4 => 'Chicken']

When no items are filtered, you still "get" indexes. You just get all of them

[0 => 'Kentucky', 1 => 'Fried', 2 => 'Chicken']

But, in PHP, that gets "simplified" to

['Kentucky', 'Fried', 'Chicken']

PHP's weird numeric indexes are the culprit here. This has ramifications when you're returning JSON (one returns an object, one an array). I wish that PHP treated Map-Like Arrays and Array-Like Arrays more separately than this though.

Take this last example

array_keys([1, 2, 3]);

This will return

[0, 1, 2]

Any array, no matter what, has keys. That just really confuses JSON serializers I guess. In fact, now I'm curious how the serializers know when to differentiate between arrays and objects. It must be whenever the indices start at 0 and follow sequentially, in order, after that.

1 like
gaura's avatar

@natepisarski See my post a couple of posts below about an inconsistency in Laravel's documentation.

BillRiess's avatar

This makes sense, thanks for the explanation!

gaura's avatar

This post is little dated but I want to point out to an inconsistency in the Laravel documentation here which is relevant to this post.

https://laravel.com/docs/12.x/collections#method-filter. This link shows an example that's produced below.

$collection = collect([1, 2, 3, 4]);
 
$filtered = $collection->filter(function (int $value, int $key) {
    return $value > 2;
});
 
$filtered->all();
 
// [3, 4]

The above output is clearly wrong. The actual output has keys like so:

[
   2 => 3,
   3 => 4,
]

Please or to participate in this conversation.