如何避免未定义的偏移量错误

65

如何轻松避免出现此错误/提示:

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

...在这段代码中:

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

explode并不总是返回两个值,但如果你想使用list()函数,如何避免出现notice提示?

8个回答

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

有两个改动:

  • 它通过限制 explode() 返回的数组大小为2来实现。似乎不需要更多
  • 如果返回的值少于两个,它会追加 null 直到数组包含2个值。有关更多信息,请参见手册:array_pad()

这意味着,如果 $value 中没有 |,则 $field === null。当然,您可以使用任何您喜欢定义为 $field 默认值(而不是 null)的值。也可以交换 $func$field 的行为。

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

现在$funcnull,当$value中没有|时。


13

我不知道有没有直接的方法可以做到这一点,同时还保留了方便性。

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

不过,既然现在无法直接实现,那么您可以考虑一种隐蔽的间接方法:

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

我已经向$value添加了尽可能多的|,以确保explode在数组中至少生成2个项目。 对于n变量,添加n-1个分隔符。

这样做可以避免出现错误,同时保持方便的list赋值,任何输入中不存在的值都将设置为空字符串。对于大多数情况而言,后者不应该会给您带来任何问题,因此上述方法应该可行。


如果只是关于“不显示”通知,我们是否可以通过执行@explode()来抑制它?我知道这不太好看,但它确实能解决问题,对吧?如果你真的想要“避免”它,那么你绝对是正确的... - KilZone
3
@KilZone说,这并不是关于“不展示”,而是关于“代码的编写方式是如果它出现错误,那么就已经存在一个bug”的思维方式。另外,最好尽量避免使用@操作符。你知道在文档中对该操作符的警告吗?我曾多次因此犯错。 - Jon
好的,我明白你(和clarkk)的观点,我只是随便问问。哦,是的,我知道那个警告,这不会是我第一次盯着一个应该出现的页面看空白屏幕了。 - KilZone
真的很遗憾!他们在想什么呢... :-( - Déjà vu

4
这对我有用:

这个方法适用于我:

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

我同意你的看法,@bart。在大多数情况下是正确的,但在这种特定情况下,我认为没有主要问题,可以使用它。 - Delmo

3
当您尝试将字符串拆分为 ($value) 时,如果该字符串中没有所需内容,则会出现 undefined offset 错误。
这个问题与这个问题非常相似:undefined offset when using php explode(),其中有更详细的解释,可以完全解决您的问题。
至于检查 '|' 的出现以防止错误,您可以这样做:
$pos = strpos($value,'|');

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

希望这能帮到你。

@Down Voter,您介意解释一下原因吗?如果我犯了错误而被downvote,我并不介意,但如果您能解释一下为什么,我就可以纠正我的帖子,并从中学习到我的错误所在!谢谢。 - Jack Franklin
即使 strpos 返回 true,仍然可能会出现错误。$value = 'almost|perfect'; $pos = strpos($value,'|'); if ($pos === true) { list($one, $two, $three) = explode('|', $value); } - David Kmenta

2

我可能会将此分为两个步骤。

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

也许有更快更简洁的方法。

这样做会使$field未定义,这几乎比未定义索引更糟糕。 - phant0m
是的,你说得对。我已经添加了一行代码,以防它之前已经定义过了,将其设置为NULL。但无论如何,在使用之前,我认为你应该检查$field的值。 - Andreas Jansson

1
if (count(explode('|', $value))==2)
  list($func, $field) = explode('|', $value);

然而,它略微不太优化。


1
为什么要爆炸两次?为什么不只检测是否存在管道字符,然后进行分割? - Jared Farrish

1

我想提到一个我使用了几十年的更通用的实用函数。它过滤掉空值并修剪空格。它还使用 array_pad() 确保您至少获得所请求的值(由 @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;
}

1
我经常遇到这个问题,所以我想要一个函数,可以更好地语法化,而不必在数组或字符串中添加不必要的填充。
// 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);

针对我的需求,我通常使用数组进行操作,但您可以编写类似的函数,包括explode函数,如下所示...

// 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);

需要PHP5.6或更高版本支持可变参数函数: http://php.net/manual/en/functions.arguments.php#functions.variable-arg-list


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接