Foreach için verilen Geçersiz değişken()


304

Çoğu zaman bir dizi veya boş değişken olabilen verileri işlemek ve bazılarını foreachbu verilerle beslemek sık sık olur .

$values = get_values();

foreach ($values as $value){
  ...
}

Bir foreach'i dizi olmayan verilerle beslediğinizde bir uyarı alırsınız:

Uyarı: [...] içinde foreach () için geçersiz argüman sağlandı

get_values()Her zaman bir dizi (geriye dönük uyumluluk, kullanılabilir kaynak kodu, başka bir sebep ne olursa olsun) döndürmek için işlevi yeniden düzenlemenin mümkün olmadığını varsayarsak , bu uyarıları önlemek için hangisinin en temiz ve en etkili yol olduğunu merak ediyorum:

  • Döküm $valuesdiziye
  • $valuesDiziye başlatılıyor
  • Ambalaj foreachbir ileif
  • Diğer (lütfen önerin)

Oldukça mümkün $valuesbir dizi değil.
Bhargav Nanekalva

Yanıtlar:


509

Şahsen bunu en temiz buluyorum - en etkili olup olmadığından emin değilim, zihin!

if (is_array($values) || is_object($values))
{
    foreach ($values as $value)
    {
        ...
    }
}

Tercihimin nedeni, yine de başlayacak bir şeyiniz olmadığında boş bir dizi ayırmamasıdır.


4
Veya dizi boş olmadığını anlamak için count () işlevini kullanın
Kemo

76
@Kemo: count()güvenilir değil. Eğer başarılı olursa count()null adlı, bu Eğer başarılı olursa 0 döndürür boş olmayan, dizi olmayan argüman, bu döner 1. Bu nedenle kullanımı imkansız count()değişken boş bir dizi olabilir zaman değişkeni, bir dizi olup olmadığını belirlemek için ya da 1 öğe içeren bir dizi.
Andy Shellam

12
Bazı nesnelerin yinelenebilir olduğunu ve bu cevabın bunları hesaba katmadığını unutmayın.
Brad Koch

32
Olmalı if (is_array($values) || $values instanceof Traversable).
Bob Stein

3
Yine de en verimli olmadığını söylemek için gitmediği bir utanç: D
Gui Prá

116

Buna ne dersin? çok temiz ve hepsi tek bir satırda.

foreach ((array) $items as $item) {
 // ...
 }

7
Benim için işe yarayan tek şey bu. Bazı nedenlerden dolayı PHP, oluşturduğum çok boyutlu dizinin aslında bir dizi dizisi olduğuna inanmıyordu.
Justin

1
Aynı şekilde, bu dizi veya boş değer içeren bir dizi için çok güzel bir düzeltme. Veriler boşsa devam etmek için foreach döngüsüne bir test eklemeniz yeterlidir.
Lizardx

Sorunumu çözdüm. Teşekkürler!
Hitesh

1
Parlak kod, $ _POST onay kutusunu kullanarak dizi ve hiçbiri dizi değeri için if, else atladı!
Yann Chabot

2
NOT: Güzel görünümlü ve geçersiz foreach uyarısını çözerken, değişken herhangi bir şekilde ayarlanmamışsa bu yöntem tanımsız bir değişken uyarısı döndürür. Kullanım isset()veya is_array()veya her ikisi, tamamen vb senaryoya göre
James

42

Genellikle buna benzer bir yapı kullanırım:

/**
 * Determine if a variable is iterable. i.e. can be used to loop over.
 *
 * @return bool
 */
function is_iterable($var)
{
    return $var !== null 
        && (is_array($var) 
            || $var instanceof Traversable 
            || $var instanceof Iterator 
            || $var instanceof IteratorAggregate
            );
}

$values = get_values();

if (is_iterable($values))
{
    foreach ($values as $value)
    {
        // do stuff...
    }
}

Bu belirli sürümün test edilmediğini, doğrudan bellekten SO'ya yazıldığını unutmayın.

Düzenleme: Eklenebilir çek eklendi


3
En iyi cevap. Bence gerçekten kontrol etmelisin $var instanceof Traversable. Buraya bakın . Çünkü örneğin, bir SimpleXMLElement öğesini öngörebilirsiniz , ancak bu Iterator veya IteratorAggregate örneği değildir.
Bob Stein

2
Diğer iki sınıfı kaldırabilirsiniz, @Kris. Her ikisi de şimdi Traversable'ı genişletiyor ve 5.0.0'da bu şekilde doğmuş gibi görünüyor. Yine de, instanceof'in her zaman uzaya uygulanmış olup olmadığı konusunda küçük bir şüphe hissediyorum.
Bob Stein

1
@ BobStein-VisiBone: evet (sınıflar değil, arayüzler hariç) Ancak; Traversable'ı bunlardan önce koydum, ne Iterator ne de IteratorAggregate'in hiç doğrulamaya ihtiyacı olmayacaktı (bu şekilde yürütmeyi yavaşlatmayacaklar). Cevabı verdiğim orijinal cevaba olabildiğince yakın tutmak ve açık / okunabilir tutmak için bıraktım.
Kris

2
Sanırım is_object($var)yeniden eklemek adil olur . php.net/manual/en/language.oop5.iterations.php
Mark Fox

1
@ MarkFox: çekinmeyin, ancak bilerek dışarıda bıraktım; Bunun için daha iyi uygulanmayan bir kullanım görmedim Iteratorveya IteratorAggregate, ama bu sadece benim fikrim ve bunun için öznel (asla kamu alanlarını kullanmıyorum).
Kris

15

Diğerleri bir hatayı önlemek için geçerli bir seçenek olarak önermekle birlikte, lütfen bir çözüm olarak yayınlamaya bağımlı olmayın , başka birine neden olabilir.

Unutmayın: Belirli bir dizi biçiminin döndürülmesini beklerseniz, bu başarısız olabilir. Bunun için daha fazla kontrol gereklidir.

Örneğin, bir dizi için bir mantıksal döküm (array)boololacak değil boş bir dizi olur, ancak birinin bir int mantıksal değeri içeren eleman içeren bir dizi: [0=>0]ya da [0=>1].

Bu sorunu sunmak için hızlı bir test yazdım . ( İlk test URL'sinin başarısız olması durumunda bir yedek Test aşağıda verilmiştir .)

: Testleridir Dahil null, false, true, bir class, bir arrayve undefined.


Her zaman foreach kullanmadan önce girişinizi test edin. Öneriler:

  1. Hızlı tip kontrolü :$array = is_array($var) or is_object($var) ? $var : [] ;
  2. Bir foreach kullanmadan ve dönüş türlerini belirtmeden önce yöntemlerde ipucu dizileri yazın
  3. İçinde her foreach sarma
  4. try{}catch(){}Blokları kullanma
  5. Üretimden önce uygun kod / test tasarımı
  6. Bir diziyi uygun forma karşı test etmek için array_key_existsbelirli bir anahtarda kullanabilirsiniz veya bir dizinin derinliğini test edebilirsiniz (bir olduğunda!) .
  7. Yinelenen kodu azaltacak şekilde her zaman yardımcı yöntemlerinizi genel ad alanına çıkarın

8

Bunu dene:

//Force array
$dataArr = is_array($dataArr) ? $dataArr : array($dataArr);
foreach ($dataArr as $val) {
  echo $val;
}

;)


1
Bu ilişkisel dizilerle iyi sonuç vermez .. is_array yöntemi genel olarak daha iyi ... ve daha kolay ...
AO_

4
$values = get_values();

foreach ((array) $values as $value){
  ...
}

Sorun her zaman sıfırdır ve Döküm aslında temizleme çözeltisidir.


3

Her şeyden önce, her değişken başlatılmalıdır. Her zaman.
Döküm bir seçenek değil.
get_values ​​(); farklı tip değişkeni döndürebilir, bu değer elbette kontrol edilmelidir.


Döküm bir seçenektir - kullanarak bir dizi başlatırsanız $array = (array)null;boş bir dizi elde edersiniz. Tabii ki bu bellek ayırma israfı ;-)
Andy Shellam

2
+1: duygusal bir bakış açısıyla okuyun, dilin yapamayacağı umurumda değil, değişkenler bildirilmeli ZORUNLU ve güvenilir olmayan sonuçlar kontrol edilmelidir ZORUNLU . Geliştirici (ler) aklı başında tutmak gerekir ve hata günlükleri kısa.
Kris

3

@ Kris'in kodunun daha kısa bir uzantısı

function secure_iterable($var)
{
    return is_iterable($var) ? $var : array();
}

foreach (secure_iterable($values) as $value)
{
     //do stuff...
}

özellikle şablon kodunun içinde kullanmak için

<?php foreach (secure_iterable($values) as $value): ?>
    ...
<?php endforeach; ?>

2
Bunu mu demek istediniz return is_iterable($var) ? $var : array($var);?
SQB

3

Php7 kullanıyorsanız ve yalnızca tanımsız hataları işlemek istiyorsanız, bu en temiz IMHO'dur

$array = [1,2,3,4];
foreach ( $array ?? [] as $item ) {
  echo $item;
}

2
foreach ($arr ? $arr : [] as $elem) {
    // Does something 
}

Bu, bir dizi olup olmadığını kontrol etmez, ancak değişken null veya boş bir dizi ise döngüyü atlar.


1

Bu durumda olup olmadığından emin değilim ama bu sorun wordpress sitelerini taşırken veya genel olarak dinamik siteleri taşırken birkaç kez ortaya çıkıyor gibi görünüyor. Bu durumda, taşıdığınız barındırma işleminin eski sitenizin kullandığı PHP sürümünü kullandığından emin olun.

Sitenizi geçiriyorsanız ve bu sadece gelmiş bir sorun PHP 5 güncellemeyi deneyin. Bu, bu sorunların bazılarını halleder. Aptalca bir çözüm gibi görünebilir ama benim için hile yaptı.


1

Her foreach döngüsünün içinde diziyi null değerine ayarlarsanız, bu bildirim için istisnai durum oluşur

if (is_array($values))
{
    foreach ($values as $value)
    {
        $values = null;//WARNING!!!
    }
}

1

Bu çözüme ne dersiniz:

$type = gettype($your_iteratable);
$types = array(
    'array',
    'object'
);

if (in_array($type, $types)) {
    // foreach code comes here
}

1

foreach()Görüntülü tweetler için geçersiz argüman sağlandı . gidin /wp-content/plugins/display-tweets-php. Sonra bu kodu 591 numaralı satıra yerleştirin, Mükemmel çalışır.

if (is_array($tweets)) {
    foreach ($tweets as $tweet) 
    {
        ...
    }
}

Müthiş! Kabul edilen çözüm bu olmalı. benim durumumda bunu ekledim:if (is_array($_POST['auto'])){ // code }
Jodyshop

0

Ayrıca çevre ile bir ilişki var gibi görünüyor:

Ben sadece dev ortamında, ancak prod (bu sunucu üzerinde çalışıyorum, localhost değil) çalışıyorum "geçersiz argüman sağlanan foreach ()" hatası vardı.

Hataya rağmen, bir var_dump dizinin iyi olduğunu belirtti (her iki durumda da app ve dev).

if (is_array($array))etrafındaforeach ($array as $subarray) sorunu çözdü.

Üzgünüm, sebebini açıklayamıyorum, ancak bir çözüm bulmam biraz zaman aldığından bunu bir gözlem olarak daha iyi paylaşmayı düşündüm.


0

Diziyi foreach döngüsüne geçireceğiniz zaman is_array işlevini kullanın.

if (is_array($your_variable)) {
  foreach ($your_variable as $item) {
   //your code
}
}

0

Boş bir diziyi boşsa yedek olarak tanımlamaya ne dersiniz get_value()?
En kısa yolu düşünemiyorum.

$values = get_values() ?: [];

foreach ($values as $value){
  ...
}

0

Ben bir arada kullanacağız empty, issetve is_arrayolarak

$array = ['dog', 'cat', 'lion'];

if (!empty($array) && isset($array) && is_array($array) {
    //loop
    foreach ($array as $values) {
        echo $values; 
    }
}

-3

Andy ile aynı şeyi yaparım ama 'boş' işlevini kullanacağım.

şöyle:

if(empty($yourArray))
{echo"<p>There's nothing in the array.....</p>";}
else
{
foreach ($yourArray as $current_array_item)
  {
    //do something with the current array item here
  } 
}

3
-1, $yourArray = 1;yinelemeye çalışacak ve hatayı alacaksınız. empty()uygun bir test değildir.
Brad Koch

@BradKoch kesinlikle doğru. is_array (), $ yourArray öğesinin bir dizi olup olmadığını test etmenin tek güvenilir yoludur. İs_array () işlevinin neden yeterli olmadığına ilişkin ayrıntılar için diğer yanıtlara bakın - foreach yineleyicileri de işleyebilir.
cgeisel
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.