Bagaimana cara memeriksa apakah variabel adalah array?… Atau sesuatu seperti array

90

Saya ingin menggunakan foreachloop dengan variabel, tetapi variabel ini dapat memiliki banyak jenis, NULLmisalnya.

Jadi sebelum foreachsaya mengujinya:

if(is_array($var)){
  foreach($var as ...

Tetapi saya menyadari bahwa itu juga bisa menjadi kelas yang mengimplementasikan Iteratorantarmuka. Mungkin saya buta tapi bagaimana cara memeriksa apakah kelas mengimplementasikan antarmuka? Apakah ada sesuatu seperti is_afungsi atau inheritsoperator? Saya menemukan class_implements, saya dapat menggunakannya, tetapi mungkin ada sesuatu yang lebih sederhana?

Dan kedua, yang lebih penting, saya kira fungsi ini ada, akan cukup untuk memeriksa apakah variabel is_arrayatau "mengimplementasikan Iteratorantarmuka" atau haruskah saya menguji sesuatu yang lebih?

Voitcus
sumber
2
if ($ var instanceof ArrayIterator)
Alexey
Ya, saya sangat yakin ini tidak akan berhasil yang bahkan belum melihat ke manual ...
Voitcus
2
Kemungkinan duplikat dari objek Iterable dan petunjuk tipe array?
Blackhole

Jawaban:

80

Jika Anda menggunakan foreachinside sebuah fungsi dan Anda mengharapkan sebuah array atau objek Traversable, Anda dapat mengetik petunjuk yang berfungsi dengan:

function myFunction(array $a)
function myFunction(Traversable)

Jika Anda tidak menggunakan foreachinside sebuah fungsi atau mengharapkan keduanya, Anda dapat menggunakan konstruksi ini untuk memeriksa apakah Anda dapat melakukan iterasi pada variabel:

if (is_array($a) or ($a instanceof Traversable))
Sepatu
sumber
Terima kasih. Saya berharap itu cukup dan tidak akan ada konstruksi bahasa lain yang dapat diulang.
Voitcus
Saya merasa is_arraymahal. Biaya komputasi sepertinya meningkat dengan ukuran array (yang tidak masuk akal karena hanya memeriksa apakah itu array). Tapi itu terjadi pada saya secara mengejutkan di perpustakaan. Lihat komentar saya di pertanyaan terkait. Akan instanceof Traversablebekerja dengan array? Saya tidak sempat menguji performanya.
ADTC
@ADTC AFAIR array adalah turunan dari Traversablejadi ya.
Sepatu
1
@Shoe Saya mencobanya di sini . Dengan $var = array(1,2,3);hasil sebagai berikut: is_array($var) = truedan $var instanceof Traversable = false.
ADTC
@ADTC Ya, baru saja diperiksa. Array tidak diimplementasikan Iteratordan karenanya tidak berfungsi Traversable.
Sepatu
15

foreachdapat menangani array dan objek. Anda dapat memeriksanya dengan:

$can_foreach = is_array($var) || is_object($var);
if ($can_foreach) {
    foreach ($var as ...
}

Anda tidak perlu memeriksanya secara khusus karena Traversableorang lain telah mengisyaratkan dalam jawaban mereka, karena semua objek - seperti semua array - dapat dilintasi dalam PHP.

Lebih teknis:

foreachbekerja dengan semua jenis traversable, yaitu dengan array, dengan objek biasa (di mana properti yang dapat diakses dilintasi) dan Traversableobjek (atau lebih tepatnya objek yang mendefinisikan get_iteratorpenangan internal ).

( sumber )

Secara sederhana dikatakan dalam pemrograman PHP umum, setiap kali ada variabel

  • sebuah larik
  • Sebuah Objek

dan tidak

  • BATAL
  • sebuah sumber daya
  • skalar

Anda dapat menggunakannya foreach.

hakre
sumber
5

Anda dapat memeriksa instance Traversabledengan fungsi sederhana. Ini akan berhasil untuk semua ini IteratorkarenaIterator extends Traversable

function canLoop($mixed) {
    return is_array($mixed) || $mixed instanceof Traversable ? true : false;
}
Baba
sumber
"? true: false" bagian adalah redundan. instanceof sudah memberikan nilai bool sebagai hasilnya.
Linas
2
<?php
$var = new ArrayIterator();

var_dump(is_array($var), ($var instanceof ArrayIterator));

kembali bool(false)ataubool(true)

Alexey
sumber
0

Fungsi

<?php

/**
 * Is Array?
 * @param mixed $x
 * @return bool
 */
function isArray($x) : bool {
  return !isAssociative($x);
}

/**
 * Is Associative Array?
 * @param mixed $x
 * @return bool
 */
function isAssociative($x) : bool {
  if (!is_array($array)) {
    return false;
  }
  $i = count($array);
  while ($i > 0) {
    if (!isset($array[--$i])) {
      return true;
    }
  }
  return false;
}

Contoh

<?php

$arr = [ 'foo', 'bar' ];
$obj = [ 'foo' => 'bar' ];

var_dump(isAssociative($arr));
# bool(false)

var_dump(isAssociative($obj));
# bool(true)

var_dump(isArray($obj));
# bool(false)

var_dump(isArray($arr));
# bool(true)
Eduardo Cuomo
sumber
0

Sejak PHP 7.1 ada tipe pseudo iterableuntuk tujuan ini. Mengisyaratkan tipe iterablemenerima larik apa pun serta implementasi Traversableantarmuka apa pun. PHP 7.1 juga memperkenalkan fungsi tersebut is_iterable(). Untuk versi yang lebih lama, lihat jawaban lain di sini untuk menyelesaikan penerapan jenis yang setara tanpa fitur bawaan yang lebih baru.

Permainan yang adil: Seperti yang ditunjukkan BlackHole, pertanyaan ini tampaknya merupakan duplikat dari objek Iterable dan petunjuk tipe array? dan jawabannya lebih detail dari saya.

sinyal lemah
sumber