Avoid PHP notice when destructuring array [duplicate]
Asked Answered
P

4

29

Let's say we have an array, and we try to get the value of a key which does not exist:

$arr = ['a', 'b'];
$val0 = $arr[0] ?? null;
$val1 = $arr[1] ?? null;
$val2 = $arr[2] ?? null;

Because of the null coalescing operator, this will not emit any notices, regardless of whether the array elements exist.


In PHP7.1 symmetric array destructuring was introduced; it is helpful, but this code:

[$val0, $val1, $val2] = $arr;

will emit an Undefined index: 2 in $arr ... notice.

Is it possible to destructure the array while avoiding these notices?

Petulant answered 16/2, 2018 at 12:18 Comment(9)
If you know what keys the array should have why not merge them before doing anything else? $ourArray = array_merge(['a' => null, 'b' => null, 'c' => null], $ourArray);Coryden
Your example of array destructing doesn't make sense...Strenta
@JonStirling could you tell me please why it doesnt make any sense?Petulant
The documentation doesn't mention this style of destructuring. Why do you think it should be possible like this, using dictionary "flavor" of the arrays on the receiving side?Dana
@SergioTulentsev It seems to be OK syntax - link to the RFCCoryden
@h2ooooooo: ah, so one misses just the keyword list here?Dana
@SergioTulentsev No, the keyword "list" is the oldschool way of doing it, kinda like doing $foo = array(1, 2, 3); instead of $foo = [1, 2, 3]; the code works fine but his code is complaining that the c key is not defined (notice how the first one throws a notice?)Coryden
@h2ooooooo: got it, thanks. In ruby, this would have worked just fine: a, b, c = ourArray.values_at('a', 'b', 'c'), where c would be nil. Maybe similar api exists here.Dana
@SergioTulentsev Using the error suppression operator that Michas mentioned is probably the easiest way without doing merging of the array or filling with NULL. I wasn't aware of this new syntax either. Personally I'd probably go for a different solution all together.Coryden
P
46

You can use the @ operator.
https://secure.php.net/manual/en/language.operators.errorcontrol.php

@[$val0, $val1, $val2] = $arr;

Disclaimer
This operator is controversial. It may hide useful errors messages from function calls. A lot of programmers will avoid it even for hight cost. For assignments it is safe though.


Based on comment by h2ooooooo.

If you are able to define defaults for all your values, you can use code below.

[$val0, $val1, $val2] = $arr + $defaults;

The operator + is important. The function array_merge will not preserve numeric keys.

The definition for $defaults may look like this:

$defaults = array_fill(0, 3, null);

Or you can manually define values for every possible key.

Perversity answered 16/2, 2018 at 12:32 Comment(6)
No clue who downvoted you (probably just for hiding errors in general). This answer works.Coryden
Many developers discourage the "stfu operator". Yes, it works, but it generally indicates a hacky solution that should be replaced by something more appropriate (I didn't downvote).Unclasp
I would also accept @Coryden solution: $ourArray = array_merge(['a' => null, 'b' => null, 'c' => null], $ourArray);Petulant
You can simplify the $defaults definition by doing something like $defaults = array_fill_keys(['a', 'b', 'c', 'd', 'e', 'f'], null);Coryden
Neither of these solutions work on a foreach statement, unfortunately.Apospory
The option to have defaults is a perfect solution for destructuring an explode($separator, $string) when you have determined -as a developer decision- the number of possibilities that will come out from and that you will use.Intine
E
17

You could try ensuring the key exists in the array, by merging some defaults:

[$val0, $val1, $val2] = $arr + [2 => null];
Ecstatic answered 16/2, 2018 at 12:45 Comment(0)
U
1

I think the other answers are correct that providing default values for any possibly missing elements is the best way to prevent the notice (actually it's now a warning in PHP 8), but it may be simpler to use array_pad to do this.

[$val0, $val1, $val2] = array_pad($arr, 3, null);

No need to create/merge a second array of defaults. Just pad it to a length of however many variables you're trying to define.

Example: https://3v4l.org/lmJ42

Ullage answered 8/7 at 19:0 Comment(0)
M
0

I like to use array_replace for this kind of stuff:

$input = ['foo'];

[$first, $second] = array_replace([null, null], $input);

var_export(compact('first', 'second'));

Output:

array ( 'first' => 'foo', 'second' => NULL, )

Learn more about array_replace: https://www.php.net/manual/en/function.array-replace.php

Mohandas answered 8/7 at 18:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.