65

How can you easily avoid getting this error/notice:

Notice: Undefined offset: 1 in /var/www/page.php on line 149

... in this code:

list($func, $field) = explode('|', $value);

There are not always two values returned by explode, but if you want to use list() how can you then easily avoid the notice?

clarkk
  • 27,151
  • 72
  • 200
  • 340

8 Answers8

133
list($func, $field) = array_pad(explode('|', $value, 2), 2, null);

Two changes:

  • It limits the size of the array returned by explode() to 2. It seems, that no more than this is wanted
  • If there are fewer than two values returned, it appends null until the array contains 2 values. See Manual: array_pad() for further information

This means, if there is no | in $value, $field === null. Of course you can use every value you like to define as default for $field (instead of null). Its also possible to swap the behavior of $func and $field

list($func, $field) = array_pad(explode('|', $value, 2), -2, null);

Now $func is null, when there is no | in $value.

menna
  • 3
  • 1
KingCrunch
  • 128,817
  • 21
  • 151
  • 173
13

I don't know of a direct way to do this that also preserves the convenience of

list($func, $field) = explode('|', $value);

However, since it's really a pity not to be able to do this, you may want to consider a sneaky indirect approach:

list($func, $field) = explode('|', $value.'|');

I have appended to $value as many |s as needed to make sure that explode will produce at least 2 items in the array. For n variables, add n-1 delimiter characters.

This way you won't get any errors, you keep the convenient list assignment, and any values which did not exist in the input will be set to the empty string. For the majority of cases, the latter should not give you any problems so the above idea would work.

Jon
  • 428,835
  • 81
  • 738
  • 806
  • If it's all about 'not showing' the notice, can't we just suppress it by doing @explode()? I know it's not pretty, but it does the trick right? If you really want to 'avoid' it, well then you're absolutely right... – KilZone Jul 04 '11 at 21:56
  • 3
    @KilZone: It's not really about "not showing" it, but rather in the mindset of "this code is written such that if it ever gives an error, it has acquired a bug". Also, the `@` operator is best avoided if at all possible. You know [that warning](http://php.net/manual/en/language.operators.errorcontrol.php) in the documentation of the operator? I 've fell for that more than once. – Jon Jul 04 '11 at 21:59
  • Right, I can see your (and clarkk's) point, I was just wondering anyway. Ow and yes I know that warning, it wouldn't be the first time I was staring at a blank screen where my page should have been. – KilZone Jul 04 '11 at 22:03
  • Indeed, it is really a pity! What were they thinking ... :-( – Déjà vu Jul 16 '14 at 01:43
4

This worked for me:

@list($func, $field) = explode('|', $value);
Delmo
  • 2,188
  • 2
  • 20
  • 29
  • I agree with you @bart. That's true in most cases but in this specific case I can't see a major issue to don't use it. – Delmo Jan 19 '17 at 20:21
3

You get an undefined offset when the thing you're trying to explode the string by ($value) doesn't actually have it in, I believe.

This question is very much similar to this: undefined offset when using php explode(), where there is a much further explanation which should fully solve your issue.

As for checking for the occurrence of '|' as to prevent the error, you can do:

$pos = strpos($value,'|');

if(!($pos === false)) {
     //$value does contain at least one |
}

Hope this helps.

Community
  • 1
  • 1
Jack Franklin
  • 3,765
  • 6
  • 26
  • 34
  • @Down Voter would you mind explaining why? I've no problems with being downvoted if I've made an error, if you could explain why I can correct the post & also learn from where I've gone wrong! Cheers. – Jack Franklin Jul 05 '11 at 08:29
  • You can still get error even if `strpos` returns `true`. `$value = 'almost|perfect'; $pos = strpos($value,'|'); if ($pos === true) { list($one, $two, $three) = explode('|', $value); }` – David Kmenta Feb 05 '18 at 11:00
2

I'd probably break this up into two steps

$split = explode('|', $value);
$func = $split[0];
if(count($split) > 1)
  $field = $split[1];
else
  $field = NULL;

There's probably a quicker and neater way though.

Andreas Jansson
  • 3,137
  • 2
  • 30
  • 40
  • This would leave `$field` undefined though, which is hardly any better than an undefined index. – phant0m Jul 04 '11 at 21:55
  • Yes you're right. I've added a line to set it to NULL in case it's been previously defined. But in any case, I reckon you'd want to check the value of $field before you use it. – Andreas Jansson Jul 04 '11 at 21:58
1

I often come across this issue, so I wanted a function that allowed something nicer syntactically without unnecessarily padding the array or string.

// Put array entries in variables. Undefined index defaults to null
function toVars($arr, &...$ret)
{
    $n = count($arr);
    foreach ($ret as $i => &$r) {
        $r = $i < $n ? $arr[$i] : null;
    }
}

// Example usage
toVars(explode('|', $value), $func, $field);

For my purposes, I'm usually working with an array, but you could write a similar function that includes the explode function, like this...

// Explode and put entries in variables. Undefined index defaults to null
function explodeTo($delimiter, $s, &...$ret)
{
    $arr = explode($delimier, $s);
    $n = count($arr);
    foreach ($ret as $i => &$r) {
        $r = $i < $n ? $arr[$i] : null;
    }
}

// Example usage
toVars('|', $value, $func, $field);

Requires PHP5.6 or above for variadic function: http://php.net/manual/en/functions.arguments.php#functions.variable-arg-list

xtempore
  • 5,260
  • 4
  • 36
  • 43
1

Want to mention a more general utility function that I use since decades. It filters out empty values and trims spaces. It also uses array_pad() to make sure you get at least the requested amount of values (as suggested by @KingCrunch).

/**
 * Does string splitting with cleanup.
 * Added array_pad() to prevent list() complaining about undefined index
 * @param $sep string
 * @param $str string
 * @param null $max
 * @return array
 */
function trimExplode($sep, $str, $max = null)
{
    if ($max) {
        $parts = explode($sep, $str, $max); // checked by isset so NULL makes it 0
    } else {
        $parts = explode($sep, $str);
    }
    $parts = array_map('trim', $parts);
    $parts = array_filter($parts);
    $parts = array_values($parts);
    $parts = array_pad($parts, $max, null);
    return $parts;
}
Slawa
  • 1,141
  • 15
  • 21
1
if (count(explode('|', $value))==2)
  list($func, $field) = explode('|', $value);

However it's slightly not optimal.

Dennis Crane
  • 461
  • 2
  • 7