web-dev-qa-db-fra.com

Comment gérer le décalage non défini dans laravel?

Je reçois cette erreur lorsque j'atterris sur la page après m'être connecté:

ErreurException dans la ligne compiled.php 11573: offset non défini: 0 (vue: C:\xampp\htdocs\campusguru\resources\views\home.blade.php)

Je sais que la cause de cette erreur est la variable vide que j'ai transmise à la vue.

J'ai déjà essayé:

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

et en vue de lame comme:

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

Y at-il de toute façon je pourrais gérer cette erreur. Ou y a-t-il une meilleure façon de le faire?

15
vs_lala

Le problème est que $blogs est en réalité défini et que sa valeur est [] (c'est-à-dire vide array), ce qui signifie que l'instruction isset($blogs) sera évaluée à true. La même chose est valable pour les collections. Si une collection est vide (c'est-à-dire qu'elle ne contient aucun élément mais qu'elle est définie), isset($blogs) sera toujours évalué à true mais l'accès à $blogs[0] provoquera une erreur Undefined offset: 0.

Vous pouvez essayer les solutions suivantes:

_ {En utilisant count

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

si $blogs = [] ou $blogs = null, la fonction count retournera zéro, ce qui signifie que $blogs est vide.

_ {En utilisant empty

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

Ceci équivaut à écrire !isset($var) || $var == false comme décrit dans le manuel PHP - vide :

Résultats FALSE si var existe et a un non vide, non nul valeur. Sinon retourne VRAI.

Les éléments suivants sont considérés comme vides: 

  • "" (une chaîne vide )
  • 0 (0 sous forme d'entier)
  • 0.0 (0 en tant que float)
  • "0" (0 sous forme de chaîne)
  • NULL
  • FALSE
  • array() (un tableau vide)
  • $var; (une variable .__ déclarée, mais sans valeur)
  • Vérifier si une collection est vide

    Si $blogs est une Collection suffit pour vérifier si elle n'est pas vide à l'aide de `isNotEmpty () method:

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

    MODIFIER

    J'ai oublié d'ajouter la syntaxe de la lame:

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

    ou

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

    EDIT 2

    J'ajoute plus de contenu à cette réponse afin de résoudre certains des problèmes présentés dans les commentaires. Je pense que votre problème est le suivant:

    $blogs est une collection vide, elle est donc définie mais elle ne contient aucun élément. Pour cette raison, l'instruction if(isset($blogs)) sera évaluée à true en passant la première condition if. Dans votre modèle de lame, vous effectuez le contrôle {{ $blogs[0]->title or '' }} qui est absolument différent de<?php isset($blogs[0]->title) ? $blogs[0]->title : '' ?> comme indiqué dans les commentaires, mais il s'agit d'une expression qui renverra true ou false, de sorte qu'il ne sera jamais imprimé le paramètre title. même si $blogs[0] existe. Le problème ici est que lors de la vérification de la condition $blogs[0]->title, vous accédez réellement à l'élément 0 de la collection $blogs qui déclenchera l'exception Undefined offset: 0 car la collection est en fait vide. Ce que je disais, c'est qu'en plus de la

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

    (qui vérifie que $blogs est défini et que sa longueur est supérieure à 0) dans votre modèle, vous devez le faire

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

    ou plus concise

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

    en supposant que le flux de contrôle n'y arrivera que si le $blogs a passé la première if. Si le problème persiste, le problème est ailleurs dans votre code IMHO.

    8
    Desh901

    essayez ce qui suit:

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

    Si vous utilisez un foreach pour obtenir chaque utilisation de $ blog-> title

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

    Vous pouvez simplement résoudre ce problème avec l'assistant data_get().

    Par exemple:

    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"
    >>> 
    

    Donc dans ce cas:

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

    data_get() fonctionnera à la fois sur les tableaux et les objets, en renvoyant la clé ou l'attribut défini dans le deuxième paramètre (il peut s'agir de laravel.dot.notation.style ou simplement un tableau), le troisième paramètre sera la valeur de retour par défaut si l'objet/le tableau ou la clé/l'attribut n'existe pas, la valeur par défaut est null.


    Modifier:

    Je viens de voir la demande d'explication supplémentaire sur la raison pour laquelle le code d'origine ne fonctionnait pas.

    L'index 0 n'existe tout simplement pas sur le tableau/la collection transmis à la vue.

    >>> $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"
    

    Peu importe si OP utilisait la lame or default, elle ne parvient même pas à la déclaration ternaire à cause de l'index 0 manquant sur $blogs


    Éditez 2 comme demandé:

    Donc, la raison pour laquelle vous obtenez l'erreur Undefined offset: x est due à l'ordre dans lequel PHP évalue le code.

    Le or default de Blade est dans les coulisses rien de plus qu'une déclaration ternaire:

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

    Cela fera donc:

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

    isset() vérifiera si le titre de l'objet est défini, mais pour ce faire, il faudra que $blogs[0] soit un objet valide. Pour ce faire, il essaiera d'obtenir l'objet du tableau $blogs à l'index 0. Mais comme cet index n'existe pas, il déclenchera l'exception avec un Undefined offset: 0

    Pour que cela fonctionne avec le or default de Blade, vous devez d'abord vous assurer que $blogs[0] est défini (et de préférence aussi vérifier qu'il s'agit d'un objet, sinon vous obtiendrez la tentative d'obtenir la propriété d'erreur non-objet, veuillez noter que cela ne devrait pas être la responsabilité de la vue ), après quoi vous pourrez utiliser le or default comme vous le feriez à tout autre moment.

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

    En règle générale, vous obtiendrez la même erreur de décalage lors de l'utilisation de data_get(), car l'index 0 n'existe toujours pas.

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

    Vous pouvez jouer en sale et faire ceci ( cela ne passerait à aucune révision de code et je n’aurais pas dû taper cela du tout, c’est juste pour illustrer )

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

    Quoi qu'il en soit, avec data_get(), vous finirez toujours par faire quelque chose comme ceci, car vous devez vous assurer que $blogs[0] est quelque chose avec lequel vous pouvez travailler:

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

    En bout de ligne, la meilleure option serait pas de vous fier à des index comme celui-ci, selon vous, ce n’est tout simplement pas de votre responsabilité.

    Le or default de Blade fonctionne parfaitement sur des variables uniques, mais lorsque vous utilisez des attributs d'objet, vous devez simplement vous assurer que l'objet (parent) existe bien.

    3
    Robert

    Si vous avez un objet qui est passé à la vue et supposons que vos données sont des "posts" qui sont conservés dans un objet comme celui-ci: $ Obj-> posts.

    Si vous effectuez ensuite une boucle foreach qui parcourt chaque publication et en affiche les paramètres, comme dans l'exemple ci-dessous, cela fonctionne parfaitement lorsque vous avez des publications.

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

    Avant de faire la boucle, vous voudrez vérifier si l'attribut a été défini avec des valeurs. Vous pouvez utiliser isset () pour cela, et puisqu'il s'agit d'un formulaire spécial, il peut être utilisé comme isset ($ obj-> posts) ou isset ($ obj-> posts [0]). La différence est que ce dernier ne vérifiera que si la clé du tableau a une valeur, donc si votre clé d'index est différente de 0, elle retournera false. Par exemple, vous avez:

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

    La façon dont je ferais le chèque est la suivante:

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

    Je fais de cette façon dans le contrôleur: 

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

    OU en lame: 

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