Skip to content

Clarify Collections' interaction with Traversible<object, mixed>, such as WeakMap #49089

Closed
@Vectorial1024

Description

Laravel Version

10.33

PHP Version

8.1.5

Database Driver & Version

N/A

Description

Laravel has collect() to produce a Collection; currently, the Collection accepts many types, one of which is PHP's Traversible.

It looks fine, but a problem: WeakMap implements Traversible. From the constructor definition/hinting, WeakMap instances are valid Collection "items". But as soon as such Collections are instantiated, a fatal error is always thrown:

TypeError: Illegal offset type.

Clearly, the underlying data structure of the Collection is an array, which obviously cannot accept objects as keys.

This is quite undocumented in the official Laravel docs in the Laravel website. However, the existing Collection constructor did not really check against WeakMaps.

I do know a bit about the covariance-contravariance thing that makes it a bit difficult to specifically reject WeakMap instances during typehinting.

A clarification is very much appreciated:

  • If Collections should not accept WeakMap, then perhaps the docs should be updated with this info; or, a more specific error message could be printed.
  • If Collections are supposed to accept WeakMap, then perhaps the Collection class needs some refactoring.

One very jarring experience with Laravel, is that e.g. I can do filter() on "real array" Collections, but I cannot do filter() on WeakMap instances, even when in native PHP, both can be traversed with something like

function filter(array|WeakMap $original, callable|Closure $predicate)
{
    $results = is_array($original) ? [] : new WeakMap();
    foreach ($original as $key => $value) {
        if ($predicate($value)) {
            $results[$key] = $value;
        }
    }
    return $results;
}

Steps To Reproduce

Using php artisan tinker [file]:

File contents:

<?php

$testMap = new WeakMap();
$testInstance = new stdClass();
$testInstance->haha = 'yes';
$testMap[$testInstance] = 3;

// should the following line be allowed or rejected?
$testCollection = collect($testMap);
// TypeError: Illegal offset type

// unreachable code: unhandled exception thrown
$testCollection->each(fn($x) => var_dump($x));

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions