Skip to content

The value collection method shouldn't consider 0 as null #54910

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
phadaphunk opened this issue Mar 5, 2025 · 9 comments · May be fixed by #55512
Open

The value collection method shouldn't consider 0 as null #54910

phadaphunk opened this issue Mar 5, 2025 · 9 comments · May be fixed by #55512

Comments

@phadaphunk
Copy link

phadaphunk commented Mar 5, 2025

Laravel Version

12.x

PHP Version

8.3.15

Database Driver & Version

No response

Description

From the documentation on the value() collection method

The value method retrieves a given value from the first element of the collection

0 Should not be treated as null so the check should be specifically against null.

$collection = collect([
  ["name" => "Tim", "balance" => 0],
  ["name" => "John", "balance" => 200]
]);

$collection->value("balance");

// 200

I would expect to get Tim's debt based on the doc.

Even more so in this case,

$collection = collect([
  ["name" => "Tim", "balance" => 0],
  ["name" => "John", "balance" => 200]
]);

$collection->where('name', 'Tim')->value("balance");

// null

Same goes for all values that evaluate the same way.

$collection = collect([
  ["name" => "Tim", "vegetarian" => false],
  ["name" => "John", "vegetarian" => true]
]);

$collection->value('vegetarian');

// true

Or even a "0" string.

Steps To Reproduce

Run this code

$collection = collect([
  ["name" => "Tim", "balance" => 0],
  ["name" => "John", "balance" => 200]
]);

$collection->value("balance");

// 200

In a scenario like this, skipping a user because his balance is 0 feels wrong. The access pattern might not be the best but it's just an example of a real use case.

I know it is probably handled that way because of how PHP handles zero values but I feel this is the kind of gotcha that can be confusing to new developers using Laravel.

@phadaphunk phadaphunk changed the title The value collection methods shouldn't consider 0 as null The value collection method shouldn't consider 0 as null Mar 5, 2025
@macropay-solutions
Copy link

macropay-solutions commented Mar 5, 2025

The issue comes from this line

case '==': return $retrieved == $value;

$value is true in this case.

Dangers of using == instead of ===...

@Jamesking56
Copy link

I think changing this would become a potential breaking change

@Rizky92
Copy link

Rizky92 commented Mar 6, 2025

Use whereStrict instead.

@rodrigopedra
Copy link
Contributor

On the method:

public function value($key, $default = null)
{
if ($value = $this->firstWhere($key)) {
return data_get($value, $key, $default);
}
return value($default);
}

Changing the call to the Collection@firstWhere() method to use the Collection@first() method, would solve the issue.

You can test it out using a macro:

Artisan::command('local:test', function () {
    Collection::macro('myValue', function ($key, $default = null) {
        if ($value = $this->first()) {
            return data_get($value, $key, $default);
        }

        return value($default);
    });

    $collection = collect([
        ["name" => "Tim", "balance" => 0],
        ["name" => "John", "balance" => 200],
    ]);

    dump(
        $collection->value("balance"),   // 200
        $collection->myValue("balance"), // 0
    );
});

But I doubt they would make this change on a patch release. The Collection@value() was added 3 years ago, on PR #42257, and there is a risk of breaking code relying on the current behavior.

You could:

  • Use the macro above as a workaround for the behavior you expect, you can add it to a Service Provider so it is available throughout your project
  • Send a PR to the master branch proposing a change for the next version
  • Send a PR to the docs' repo, to clarify the expected behavior

The docs' description actually is over-simplified on the original PR's description.

Reference: https://laravel.com/docs/12.x/collections#method-value

And from what is currently on the docs, I'd also expect the behavior you described.

Maybe @stevebauman, who authored the PR which added the Collection@value() method, and is active within the community, can help out on clarifying the expected behavior. (BTW, if you read this, thanks for ImapEngine Steve, saved me a ton!)

@stevebauman
Copy link
Contributor

stevebauman commented Mar 6, 2025

Hey guys (thanks for ping @rodrigopedra)! Yea I would personally agree and consider this a bug. I would think it should return the first value where the key exists -- even if its value is null, so it operates like the Eloquent query method. Oversight on my part, my mistake!

Hard to say if this would be a breaking change since this would be the expected behavior imo!

Copy link

Thank you for reporting this issue!

As Laravel is an open source project, we rely on the community to help us diagnose and fix issues as it is not possible to research and fix every issue reported to us via GitHub.

If possible, please make a pull request fixing the issue you have described, along with corresponding tests. All pull requests are promptly reviewed by the Laravel team.

Thank you!

@macropay-solutions
Copy link

macropay-solutions commented Mar 10, 2025

@phadaphunk are you sure the first implementation requirement was to return the value from first element even if not set? Because as it is now, it returns the first value that is loosely true by looking at elements starting from first element.

@phadaphunk
Copy link
Author

@macropay-solutions From the Documentation, it sure seems like this is what the intended behaviour was

The value method retrieves a given value from the first element of the collection

You're right to point that out tho. I think it should look for the first that has the matching key and return the value regardless of it being falsy or even null. I'll adjust.

@lokeshrangani
Copy link

Maybe this can solve this issue: #55512
@phadaphunk

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment