php 如何在 Laravel 中处理未定义的偏移量?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29588597/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 00:28:42  来源:igfitidea点击:

How to handle Undefined Offset in laravel?

phplaravelundefinedoffset

提问by vs_lala

I am getting this error when I land on the page after logging in:

登录后登陆页面时出现此错误:

ErrorException in compiled.php line 11573: Undefined offset: 0 (View: C:\xampp\htdocs\campusguru\resources\views\home.blade.php)

在compiled.php line 11573中的ErrorException: Undefined offset: 0 (View: C:\xampp\htdocs\campusguru\resources\views\home.blade.php)

I know that the cause of this error is the empty variable that I passed to the view.

我知道这个错误的原因是我传递给视图的空变量。

I have already tried:

我已经尝试过:

if(isset($blog)) { do something }

and in blade view as:

并在刀片视图中为:

{{ $blogs[0]->title or '' }}

Is there anyway I could handle this error. Or is there a better way of doing it?

无论如何我可以处理这个错误。或者有更好的方法吗?

回答by iisurge

try the following:

尝试以下操作:

{{ isset($blogs[0]) ? $blogs[0]->title : '' }}

If your using a foreach to get every $blog->title use

如果您使用 foreach 来获取每个 $blog->title 使用

@foreach ($blogs as $blog)
  {{ $blog->title }}
@endforeach

回答by Desh901

The problem is that $blogsis actually defined and its value is [](i.e. empty array) so it means that isset($blogs)statement will evaluate to true. Same thing is valid for collections. If a collection is empty (i.e. has no elements but it's defined) isset($blogs)will still evaluate to truebut accessing $blogs[0]will cause an Undefined offset: 0error.

问题是$blogs实际上已定义并且其值为[](即空array),因此这意味着该isset($blogs)语句将评估为true。同样的事情对集合有效。如果集合为空(即没有元素但已定义)isset($blogs)仍将评估为,true但访问$blogs[0]将导致Undefined offset: 0错误。

You could try the following solutions:

您可以尝试以下解决方案:

Using count

使用 count

if(count($blogs)) { /* do something */ }

if $blogs = []or $blogs = nullthe function countwill return zero so that means that $blogsis empty.

if$blogs = []$blogs = null函数count将返回零,这意味着它$blogs是空的。

Using empty

使用 empty

if(!empty($blogs)) { /* do something */ }

This is the equivalent of writing !isset($var) || $var == falseas described in the PHP Manual - empty:

这相当于PHP 手册中!isset($var) || $var == false描述的写法- empty

Returns FALSEif var exists and has a non-empty, non-zero value. Otherwise returns TRUE.

The following things are considered to be empty:

  • ""(an empty string)
  • 0(0 as an integer)
  • 0.0(0 as a float)
  • "0"(0 as a string)
  • NULL
  • FALSE
  • array()(an empty array)
  • $var;(a variable declared, but without a value)
  • 如果 var 存在且具有非空、非零值,则返回FALSE。否则返回TRUE

    以下内容被认为是空的:

  • ""(空字符串)
  • 0(0 作为整数)
  • 0.0(0 作为浮点数)
  • "0"(0 作为字符串)
  • NULL
  • FALSE
  • array()(一个空数组)
  • $var;(声明的变量,但没有值)
  • Checking if a collection is empty

    检查集合是否为空

    If $blogsis a Collectionis sufficient to check if it is not empty using `isNotEmpty()method:

    If $blogsis aCollection足以使用`isNotEmpty()方法检查它是否为空:

    @if($blogs->isNotEmpty()) <!-- Do your stuff --> @endif
    

    EDIT

    编辑

    I forgot to add the blade syntax:

    我忘了添加刀片语法:

    @if(count($blogs)) <!-- Do whatever you like --> @endif
    

    or

    或者

    @if(!empty($blogs)) <!-- Do whatever you like --> @endif
    

    EDIT 2

    编辑 2

    I'm adding more content to this answer in order to address some of the issues presented in the comments. I think that your problem is the following:

    我正在为此答案添加更多内容,以解决评论中提出的一些问题。我认为你的问题如下:

    $blogsis an empty collection, so it's defined but it has no elements. For this reason the if(isset($blogs))statement will evaluate to truepassing the first ifcondition. In your blade template you are making the check {{ $blogs[0]->title or '' }}that is absolutely not equal to<?php isset($blogs[0]->title) ? $blogs[0]->title : '' ?>as pointed out in the comments, but it is an expression that will return trueor false, so it will never print out titleparameter even if $blogs[0]exists. The problem here is that when checking the condition $blogs[0]->titleyou are actually accessing the element 0of the $blogscollection that will trigger the exception Undefined offset: 0because the collection is actually empty. What i was saying is that in addition to the

    $blogs是一个空集合,所以它被定义但它没有元素。因此,该if(isset($blogs))语句将评估为true通过第一个if条件。在刀片模板你正在检查{{ $blogs[0]->title or '' }}这是绝对不等于<?php isset($blogs[0]->title) ? $blogs[0]->title : '' ?>在评论中指出的,但它是将返回一个表达式true或者false,所以它永远不会打印出title参数,即使$blogs[0]存在。这里的问题是,在检查条件时,$blogs[0]->title您实际上是在访问将触发异常的集合元素0,因为该集合实际上是空的。我要说的是,除了$blogsUndefined offset: 0

    if(count($blogs)) { /* do something */ }
    

    (that checks that $blogsis set and that it's length is greater than 0) in your template you should do

    (检查$blogs已设置并且它的长度大于0)在您的模板中您应该做

    {{ isset($blogs[0]->title) ? $blogs[0]->title : '' }}
    

    or more concisely

    或者更简洁

    {{ $blogs[0]->title ?: '' }}
    

    assuming that the control flow will arrive there only if the $blogspassed the first if. If the issue still persists the problem is elsewhere in your code IMHO.

    假设控制流只有在$blogs通过第一个if. 如果问题仍然存在,恕我直言,问题出在您的代码中的其他地方。

    回答by Robert

    You can simply solve this with the data_get()helper.

    您可以使用data_get()助手简单地解决此问题。

    For example:

    例如:

    php artisan tink
    Psy Shell v0.8.11 (PHP 7.0.22-0ubuntu0.16.04.1 — cli) by Justin Hileman
    >>> 
    >>> $a = collect([[], null, App\Models\User::find(1)]);
    => Illuminate\Support\Collection {#887
         all: [
           [],
           null,
           App\Models\User {#896
             id: 1,
             name: "user1",
             email: "[email protected]",
             last_name: "Gabrielle",
             first_name: "Rempel",
             deleted_at: null,
             created_at: "2017-08-12 15:32:01",
             updated_at: "2017-09-05 12:23:54",
           },
         ],
       }
    >>> data_get($a[0], 'name', 'nope');
    => "nope"
    >>> data_get($a[1], 'name', 'nope');
    => "nope"
    >>> data_get($a[2], 'name', 'nope');
    => "user1"
    >>> 
    

    So in this case:

    所以在这种情况下:

    {{ data_get($blogs[0], 'title', '') }}
    

    data_get()will work both on arrays and objects, returning the key or attribute defined in the second param (this can be laravel.dot.notation.style, or just an array), the 3rd param will be the default return value if the object/array or the key/attribute does not exist, the default is null.

    data_get()将适用于数组和对象,返回在第二个参数中定义的键或属性(这可以是laravel.dot.notation.style,或只是一个数组),如果对象/数组或键/属性没有,则第三个参数将是默认返回值存在,默认为空。



    Edit:

    编辑:

    Just saw the request for the extra explanation on why the original code wasn't working.

    刚刚看到关于为什么原始代码不起作用的额外解释的请求。

    Index 0 simply does not exist on the array/collection that is passed to the view.

    传递给视图的数组/集合上根本不存在索引 0。

    >>> $a = [1 => App\Models\User::find(1)];
    => [
         1 => App\Models\User {#890
           id: 1,
           name: "user1",
           // ... etc
         },
       ]
    >>> $a[0]->name ?: 'nope';
    PHP error:  Undefined offset: 0 on line 1
    >>> $a[1]->name ?: 'nope';
    => "user1"
    

    It doesn't matter if OP used the blade or default, it doesn't even make it to the ternary statement because of the missing 0 index on $blogs.

    如果 OP 使用了 Blade 并不重要or default,它甚至没有进入三元语句,因为缺少 0 索引$blogs



    Edit 2 as requested:

    根据要求编辑 2:

    So the reason you get the Undefined offset: xerror is because of the order in which PHP evaluates the code.

    所以你得到Undefined offset: x错误的原因是因为 PHP 评估代码的顺序。

    Blade's or defaultis behind the scenes nothing more than a ternary statement:

    Blade'sor default在幕后无非是一个三元声明:

    return preg_replace('/^(?=$)(.+?)(?:\s+or\s+)(.+?)$/si', 'isset() ?  : ', $value);
    

    So this will make:

    所以这将使:

    isset($blogs[0]->title) ? $blogs[0]->title : ''
    

    isset()will check if title on the object is set, but to do so, it will require $blogs[0]to be a valid object. In order to do that, it will try and get the object from the $blogsarray at index 0. But since this index does not exist, it will trigger the Exception with an Undefined offset: 0.

    isset()将检查是否设置了对象上的标题,但要这样做,它需要$blogs[0]是一个有效的对象。为了做到这一点,它会尝试从$blogs索引 0处的数组中获取对象。但由于该索引不存在,它将触发 Exception 异常Undefined offset: 0

    In order to make this work with Blade's or default, you would first have to ensure that $blogs[0]is defined (and preferably also check that it's an object, otherwise you'll get the trying to get property of non-object error, please note that this should not be the responsibility of the view), after that you would be able to use the or defaultas you would any other time.

    为了使这个与 Blade's 一起工作or default,您首先必须确保$blogs[0]已定义(最好还检查它是否是一个对象,否则您将尝试获取非对象的属性错误,请注意,这不应该是视图的责任),之后您就可以or default像其他任何时候一样使用 。

    @if (isset($blogs[0]) && is_object($blogs[0]))
        {{ $blogs[0]->title or '' }}
    @else
        // some other default placeholder
    @endif
    

    Basically you will get the same offset error when using data_get(), because index 0 still does not exist.

    基本上你会在使用时得到相同的偏移错误data_get(),因为索引 0 仍然不存在。

    {{ data_get($blogs[0], 'title', '') }} // Undefined offset: 0
    

    You could play dirty and do this (this would not pass any code review anywhere and I should not have typed this at all, this is just to illustrate)

    你可以玩得很脏然后这样做(这不会在任何地方通过任何代码,我根本不应该输入这个,这只是为了说明

    {{ data_get($blogs, '0.title', '') }} // Will display '' as it will check if key 0 exists
    

    Anyway, with data_get()you would still end up doing something like this, as you would need to make sure $blogs[0]is something you can work with:

    无论如何,data_get()你最终还是会做这样的事情,因为你需要确保$blogs[0]你可以使用:

    @if (isset($blogs[0]))
        {{ data_get($blogs[0], 'title', '') }}
    @else
        // some other default placeholder
    @endif
    

    Bottomline, the best option would be notto rely on indexes like this in your view, this is simply not the responsibility of your view.

    底线,最好的选择是不要在您的视图中依赖这样的索引,这根本不是您的视图的责任。

    Blade's or defaultworks perfectly on single variables, but when dealing with object attributes, you would just have to make sure the (parent) object exists when doing so.

    Bladeor default可以完美地处理单个变量,但是在处理对象属性时,您只需确保(父)对象存在即可。

    回答by John

    I do this way in controller:

    我在控制器中这样做:

     if (empty($allFares) || count($allFares)==0){
                return back()->withError('No Fare Found For The City!');
            }
    

    OR in blade:

    或在刀片中:

       @if (!empty($allFares) || count($allFares)>0)
                   @foreach(allFares as $key=>$value)
    
                    @endforeach
       @endif
    

    回答by Nino Korent

    If you have an object that's passed to the view and let's say your data is "posts" which is being held inside an object like this: $obj->posts.

    如果你有一个传递给视图的对象,假设你的数据是“posts”,它被保存在这样的对象中:$obj->posts。

    If you then go and do a foreach loop which would iterate trough every post and print out its parameters like in the example below it works perfectly well when you actually have posts.

    如果你然后去做一个 foreach 循环,它会遍历每个帖子并打印出它的参数,就像下面的例子一样,当你真正有帖子时,它运行得非常好。

    @foreach($obj->posts as $post)
       <h1>$post->title</h1>
       <p>$post->content</p>
    @endforeach
    

    Before doing the loop you'd want to check if attribute has been set with values. You can use isset() for this, and since it's a special form it can be used as isset($obj->posts) or isset($obj->posts[0]). The difference is that the latter will only check if the array key has any value so if your index key is anything but 0, it'll return false. For instance you have:

    在执行循环之前,您需要检查是否已使用值设置属性。您可以为此使用 isset(),并且由于它是一种特殊形式,因此可以用作 isset($obj->posts) 或 isset($obj->posts[0])。不同之处在于后者只会检查数组键是否具有任何值,因此如果您的索引键不是 0,它将返回 false。例如你有:

    $foo = ['first' => somevalue1, 'second' => somevalue2];
    isset($foo[0]); //returns false
    isset($foo['first']); //returns true
    isset($foo); //returns true
    

    The way I'd make the check is the following:

    我进行检查的方式如下:

    @if(isset($obj->posts))
       @foreach($obj->posts as $post)
          ...
       @endoforeach
    @endif
    

    回答by Haritsinh Gohil

    As of PHP7 you can use null coalescing operator ??for checking ternary conditions:

    从 PHP7 开始,您可以使用空合并运算符??来检查三元条件:

    @if($posts?? '')
     @foreach($posts as $post)
       <h1>$post->title</h1>
       <p>$post->content</p>
     @endforeach
    @endif
    

    And if you want to print any variable directly then check first that the variable exists or not in condition, so you can do as below:

    如果您想直接打印任何变量,则首先检查该变量是否存在,因此您可以执行以下操作:

    {{ $blogs && $blogs[0]->title ? $blogs[0]->title : '' }}