Skip to content
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

[5.2] Fix Arr::get($array, null) when $array is empty #12975

Merged
merged 1 commit into from
Apr 2, 2016
Merged

[5.2] Fix Arr::get($array, null) when $array is empty #12975

merged 1 commit into from
Apr 2, 2016

Conversation

thomasruiz
Copy link
Contributor

Following #12958, #12946 and #12945.

Basically, in that particular use case, when the model is created, attributes and original are both set to empty arrays. In Arr::get, we have if (! $array) { return $default; }. However, in PHP, when an array is empty, (! $array) === true.
This PR just adds to the condition the && ! is_array($array) to fix the problem.

@thomasruiz thomasruiz changed the title Fix Arr::get($array, null) when $array is empty [5.2] Fix Arr::get($array, null) when $array is empty Apr 1, 2016
@vlakoff
Copy link
Contributor

vlakoff commented Apr 1, 2016

I wasn't expecting we would go as far as empty array + null key. But we do.

A better implementation would be to move up the is_null($key) check.

@thomasruiz
Copy link
Contributor Author

Depends whether we want Arr::get(null, null, 'foo') to return null or foo. I think foo would make more sense?

@@ -184,6 +184,9 @@ public function testGet()
// Test $array not an array
$this->assertEquals('default', Arr::get(null, 'foo', 'default'));
$this->assertEquals('default', Arr::get(false, 'foo', 'default'));

// Test $array is empty
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be more like "Test $array is empty and $key is null"

@vlakoff
Copy link
Contributor

vlakoff commented Apr 1, 2016

Depends whether we want Arr::get(null, null, 'foo') to return null or foo. I think foo would make more sense?

Does this make sense at all? :p

So the alternatives are:

  • null/false array --> return default
  • null key --> return input array (so default is irrelevant)

@vlakoff
Copy link
Contributor

vlakoff commented Apr 1, 2016

Your pick, just please add a test for the choosen one :)

@taylorotwell
Copy link
Member

Is this supposed to be an or check? Seems weird to be and?

@vlakoff
Copy link
Contributor

vlakoff commented Apr 1, 2016

It means "falsy, but not an empty array".

@vlakoff
Copy link
Contributor

vlakoff commented Apr 1, 2016

We should be ok with only:

if (! is_array($array)) {
    return value($default);
}

if (is_null($key)) {
    return $array;
}

Tests:

$this->assertSame([], Arr::get([], null));
$this->assertSame([], Arr::get([], null, 'default'));
$this->assertEquals('default', Arr::get(null, null, 'default'));

@vlakoff
Copy link
Contributor

vlakoff commented Apr 1, 2016

It should rather use static::accessible:

if (! static::accessible($array)) {
    return value($default);
}

if (is_null($key)) {
    return $array;
}

@thomasruiz
Copy link
Contributor Author

I tried with only ! is_array, it doesn't work properly when using a key not null.

@vlakoff
Copy link
Contributor

vlakoff commented Apr 1, 2016

I had edited my message, can you please check again?

@thomasruiz
Copy link
Contributor Author

@vlakoff Yep, working properly with accessible. I added the tests you recommended, they make sense.

$this->assertEquals('default', Arr::get(null, null, 'default'));

// Test $array is empty and key is null
$this->assertEquals([], Arr::get([], null));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use assertSame here. I'm tired of loose typing enough :\

@dciancu
Copy link
Contributor

dciancu commented Apr 1, 2016

@thomasruiz You changed perms on the test file, you should revert them back to 644.

@vlakoff
Copy link
Contributor

vlakoff commented Apr 1, 2016

To summarize:

Previous behaviour:

  • if array is not an array, return default.
  • if array is empty, return default (as there can't be a match).
  • then, if key is null, return whole array.

Fixed behaviour:

  • if array is not an array, return default.
  • if array is empty and a key is specified, return default (no match).
  • if array is empty and key is null, return empty array. <-- that's the change
  • if key is null, return whole array.

@taylorotwell
Copy link
Member

Why is this so complicated? Arr::get has been the same for years and over the past month it seems like we have been screwing with it endlessly? Can we please stop and just make it work how it has worked for the past 4 years?

@taylorotwell
Copy link
Member

Does this make it work how it used to work?

@vlakoff
Copy link
Contributor

vlakoff commented Apr 1, 2016

I understand this can annoy you (you're not alone ;)

Problem is, the framework is relying on edge, real tricky cases of Arr::get, which weren't really determined, nor enforced by tests.

Bad news, without surprise it easily broke, good news, it gets reinforced in the process.

@vlakoff
Copy link
Contributor

vlakoff commented Apr 1, 2016

Does this make it work how it used to work?

We do our best.

@crynobone
Copy link
Member

Can we delay this to 5.3?

@thomasruiz
Copy link
Contributor Author

I'm pretty sure the code works as intended now.

@vlakoff
Copy link
Contributor

vlakoff commented Apr 1, 2016

Can we delay this to 5.3?

We are restoring previous behaviour for the case Arr::get([], null), so it has to go to 5.2.

@vlakoff
Copy link
Contributor

vlakoff commented Apr 2, 2016

For codebase consistency, we might make a similar change in Arr::has. This would produce the same results. More function calls, but codebase consistency with Arr::get. I let you decide on that.

Apart from that, PR seems good to go.

@mark86092
Copy link
Contributor

Why we need Arr::get accept null or false, as it is not designed to do so.

Arr means working on array (or array like)

@taylorotwell
Copy link
Member

STOP ARGUING ABOUT WHAT YOU THINK IT SHOULD BE. This function has been the same since like Laravel 2.0 and has NEVER caused a problem until people started screwing around with it like a month ago. STOP! Just make it how it used to work in Laravel 1, 2, 3, 4, 5.1, 5.2 until people started messing with it.

@taylorotwell taylorotwell merged commit 3a46589 into laravel:5.2 Apr 2, 2016
@mark86092
Copy link
Contributor

Oh, update my word, I mean it works GOOD now, other special cases (not designed) change is not the point as Taylor said

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants