請注意,「轉換為陣列」檢查方法已經非常過時。
在 PHP 5.6 上執行該程式碼會得到以下結果
is_array : 0.93975400924683
cast, === : 1.2425191402435
因此,請使用 'is_array',而不是可怕的轉換駭客。
(PHP 4, PHP 5, PHP 7, PHP 8)
is_array — 檢查變數是否為陣列
value
要評估的變數。
範例 #1 檢查變數是否為陣列
<?php
$yes = array('this', 'is', 'an array');
echo is_array($yes) ? 'Array' : 'not an Array';
echo "\n";
$no = 'this is a string';
echo is_array($no) ? 'Array' : 'not an Array';
?>
上述範例會輸出
Array not an Array
請注意,「轉換為陣列」檢查方法已經非常過時。
在 PHP 5.6 上執行該程式碼會得到以下結果
is_array : 0.93975400924683
cast, === : 1.2425191402435
因此,請使用 'is_array',而不是可怕的轉換駭客。
或者您可以利用 array_diff_key 和 array_key 函式
<?php
function is_assoc($var)
{
return is_array($var) && array_diff_key($var,array_keys(array_keys($var)));
}
function test($var)
{
echo is_assoc($var) ? "I'm an assoc array.\n" : "I'm not an assoc array.\n";
}
// 關聯陣列
$a = array("a"=>"aaa","b"=>1,"c"=>true);
test($a);
// 陣列
$b = array_values($a);
test($b);
// 物件
$c = (object)$a;
test($c);
// 其他型別
test($a->a);
test($a->b);
test($a->c);
?>
上述程式碼會輸出
我是一個關聯陣列。
我不是一個關聯陣列。
我不是一個關聯陣列。
我不是一個關聯陣列。
我不是一個關聯陣列。
我不是一個關聯陣列。
hperrin 的結果在 PHP 7 中確實發生了變化。現在情況正好相反,is_array 比比較快
is_array : 0.52148389816284
cast, === : 0.84179711341858
測試 1000000 次迭代。
另一個更簡單、更快的 is_assoc()
<?php
function is_assoc($array) {
foreach (array_keys($array) as $k => $v) {
if ($k !== $v)
return true;
}
return false;
}
?>
在我的測試中,它的執行速度大約是 Michael/Gabriel 的 array_reduce() 方法的兩倍。
(說到這個:Gabriel 的版本寫錯了;如果只有第一個鍵是非數值,或者鍵是數值但順序顛倒,它會將關聯陣列報告為數值。Michael 透過將 array_reduce() 與 count() 進行比較來解決這個問題,但這會消耗另一個函式呼叫;它也可以只與 -1 而不是 0 進行比較,因此從回呼中傳回 -1 作為三元運算子的 else。)
我發現了一種更快速判斷陣列的方法。如果你使用 `is_array()` 數百萬次,你會注意到*巨大*的差異。在我的機器上,這種方法大約只需要 `is_array()` 四分之一的時間。
將值強制轉換為陣列,然後檢查(使用 ===)它是否與原始值相同。
<?php
if ( (array) $unknown !== $unknown ) {
echo '$unknown 不是陣列';
} else {
echo '$unknown 是陣列';
}
?>
您可以使用此腳本來測試兩種方法的速度。
<pre>
哪種方法判斷陣列更快?
<?php
$count = 1000000;
$test = array('im', 'an', 'array');
$test2 = 'im not an array';
$test3 = (object) array('im' => 'not', 'going' => 'to be', 'an' => 'array');
$test4 = 42;
// 現在設定這個,這樣第一個 for 迴圈就不會做額外的工作。
$i = $start_time = $end_time = 0;
$start_time = microtime(true);
for ($i = 0; $i < $count; $i++) {
if (!is_array($test) || is_array($test2) || is_array($test3) || is_array($test4)) {
echo 'error';
break;
}
}
$end_time = microtime(true);
echo 'is_array : '.($end_time - $start_time)."\n";
$start_time = microtime(true);
for ($i = 0; $i < $count; $i++) {
if (!(array) $test === $test || (array) $test2 === $test2 || (array) $test3 === $test3 || (array) $test4 === $test4) {
echo 'error';
break;
}
}
$end_time = microtime(true);
echo 'cast, === : '.($end_time - $start_time)."\n";
echo "\n測試了 $count 次迭代。\n"
?>
</pre>
印出類似如下的結果
哪種方法判斷陣列更快?
is_array : 7.9920151233673
cast, === : 1.8978719711304
測試 1000000 次迭代。
alex frase 的範例速度很快,但 elanthis at awesomeplay dot com 的範例更快,而且 Ilgar 對 alex 程式碼的修改有缺陷(" || $_array[$k] !== $v" 的部分)。此外,我認為 Ilgar 在變數不是陣列時給出 false 回傳值的建議不合適,而且我認為在執行其餘程式碼之前檢查陣列是否為空也會是一個合適的檢查。
所以這是修改後的 (is_vector) 版本
<?php
function is_vector( &$array ) {
if ( !is_array($array) || empty($array) ) {
return -1;
}
$next = 0;
foreach ( $array as $k => $v ) {
if ( $k !== $next ) return true;
$next++;
}
return false;
}
?>
以及修改後的 (alex 的 is_assoc) 版本
<?php
function is_assoc($_array) {
if ( !is_array($_array) || empty($array) ) {
return -1;
}
foreach (array_keys($_array) as $k => $v) {
if ($k !== $v) {
return true;
}
}
return false;
}
?>
yousef 的範例是錯誤的,因為如果找到鍵,is_vector 會回傳 true 而不是 false
這是修正後的版本(只有 2 行不同)
<?php
function is_vector( &$array ) {
if ( !is_array($array) || empty($array) ) {
return -1;
}
$next = 0;
foreach ( $array as $k => $v ) {
if ( $k !== $next ) return false;
$next++;
}
return true;
}
?>
由 'rjg4013 at rit dot edu' 張貼的 `is_associative_array()` 和 `is_sequential_array()` 函數並不精確。
這些函數無法辨識未按順序或不在序列中的索引。例如,`array(0=>'a', 2=>'b', 1=>'c')` 和 `array(0=>'a', 3=>'b', 5=>'c')` 會被認為是序列陣列。真正的序列陣列會是連續的,索引中沒有間隙。
以下解決方案利用 `array_merge` 的特性。如果只給定一個陣列,而且該陣列是以數字索引,則鍵會以連續的方式重新索引。為了真正成為一個以數字索引的(序列)陣列,結果必須與傳遞給它的陣列匹配。否則,可以假設它是一個關聯陣列(在 C 等語言中無法實現)。
以下函數適用於 PHP >= 4。
<?php
function is_sequential_array($var)
{
return (array_merge($var) === $var && is_numeric( implode( array_keys( $var ) ) ) );
}
function is_assoc_array($var)
{
return (array_merge($var) !== $var || !is_numeric( implode( array_keys( $var ) ) ) );
}
?>
如果您不關心索引的實際順序,則可以將比較分別更改為 == 和 !=。
function is_associate_array($array)
{
return $array === array_values($array);
}
或者您可以在函數中加入 is_array 檢查
我會改變比較的順序,因為如果它真的是一個空陣列,最好在執行幾個「CPU 和記憶體密集」的函數呼叫之前就停止。
最後,在計算 1000000 次迭代的 3 個非空陣列與 1 個空陣列的比例時,它需要的時間減少了 10%。
或者反過來說
如果陣列不是空的,則需要大約 3% 到 4% 的時間,但在空陣列上至少快 4 倍。
此外,記憶體消耗也確實較少。
<?php
function is_assoc($array) {
return (is_array($array) && (count($array)==0 || 0 !== count(array_diff_key($array, array_keys(array_keys($array))) )));
}
?>
以下內容的稍微修改
<?php
function is_assoc($array)
{
return is_array($array) && count($array) !== array_reduce(array_keys($array), 'is_assoc_callback', 0);
}
function is_assoc_callback($a, $b)
{
return $a === $b ? $a + 1 : 0;
}
?>
這裡提供另一個變體函式來測試陣列是否為關聯陣列。基於 mot4h 的想法。
<?php
function is_associative($array)
{
if (!is_array($array) || empty($array))
return false;
$keys = array_keys($array);
return array_keys($keys) !== $keys;
}
?>
在 if 子句中使用 in_array 之前先使用 is_array,可以安全地跳過對可能為非陣列變數使用 in_array 時的檢查。例如:
注意:一個實際的用例可能是我們有一組可能的標誌,在資料庫中我們儲存了每個標誌是 0 還是 1。我們希望返回值為 1 的標誌列表。
我們這裡的範例不會使用太多技術性的東西,但會基於類似的邏輯來說明重點。
<?php
// 我們有一組已知的變數值
$knownVars = ['apple', 'orange'];
// 一組要檢查的值
$listToCheck = ['pear', 'banana'];
// 以及一個方法,它接受一組要檢查的值,並返回一個新的列表,
// 該列表包含從該列表中找到的有效項目...
public function getValidItemsList( $listToCheck /*['pear', 'banana']*/)
{
$returnList = [];
foreach($listToCheck as $key => $val)
{
if(in_array($val, $knownVars))
{
array_push($returnList, $val);
}
}
if(empty($returnList))
{
// 如果沒有找到有效的項目,我們有一個特殊的情況,這正是我們要討論的情況
return -1;
}
// 否則,通常會返回一個包含找到的有效項目的列表
return $returnList;
}
// 呼叫該方法並檢查是否有任何可供某些目的使用的有效項目
$validItemsList = getValidItemsList($listToCheck);
// 在這種用法中,我們可能會得到一個例外,因為
// in_array() 預期參數 #2 為陣列,檢查該值 != -1 並不能跳脫 if 語句:
if(isset($validItemsList) && $validItemsList != -1 && in_array('apple', $validItemsList))
{
//...
}
// 在這種用法中,我們安全地跳脫了 if 語句:
if(isset($validItemsList) && $validItemsList != -1 && is_array($validItemsList) && in_array('apple', $validItemsList))
{
//...
}
?>
希望這可以幫助到某些人,我知道它幫助了我。
is_assoc() 效能基準測試
<?php
function is_assoc1($array) {
if (!is_array($array)) return false;
$i = count($array);
while ($i > 0) unset($array[--$i]);
return (bool)$array;
}
function is_assoc2(&$array) {
if (!is_array($array)) return false;
$i = count($array);
while ($i > 0) {
if (!isset($array[--$i])) return true;
}
return false;
}
function is_assoc3(&$array) {
if (!is_array($array)) return false;
$i = count($array);
while ($i > 0) {
if (!array_key_exists(--$i, $array)) return true;
}
return false;
}
function is_assoc4($array) {
if (!is_array($array)) return false;
ksort($array);
foreach (array_keys($array) as $k => $v) {
if ($k !== $v) return true;
}
return false;
}
function is_assoc5(&$array) {
return is_array($array) && array_diff_key($array, array_keys($array));
}
$arr1 = array(); // not associative
$arr2 = $arr3 = array('foo', 'bar', 'baz', 'foo', 'bar', 'baz', 'foo', 'bar', 'baz', 'foo'); // not associative
asort($arr3); // not associative, shuffled keys
$arr4 = array('foo', 'bar', 'baz', 'foo', 'bar', null, 'foo', 'bar', 'baz', 'foo'); // not associative but is_assoc2() thinks it is
$arr5 = array(0 => 'foo', 1 => 'bar', 2 => 'baz', 3 => 'foo', 4 => 'bar', 5 => 'baz', 'foo3' => 'foo', 'bar3' => 'bar', 'baz3' => 'baz', 'foo4' => 'foo'); // associative
$i = $j = 0;
$time = array(0.0, 0.0, 0.0, 0.0, 0.0);
for ($j = 0; $j < 2000; $j++) {
$time[0] -= microtime(true);
for ($i = 0; $i < 1000; $i++) {
if (is_assoc1($arr1) || is_assoc1($arr2) || is_assoc1($arr3) || is_assoc1($arr4) || !is_assoc1($arr5)) {
echo 'error';
break;
}
}
$time[0] += microtime(true);
$time[1] -= microtime(true);
for ($i = 0; $i < 1000; $i++) {
if (is_assoc2($arr1) || is_assoc2($arr2) || is_assoc2($arr3) || !is_assoc2($arr4) || !is_assoc2($arr5)) { // $arr4 tweaked
echo 'error';
break;
}
}
$time[1] += microtime(true);
$time[2] -= microtime(true);
for ($i = 0; $i < 1000; $i++) {
if (is_assoc3($arr1) || is_assoc3($arr2) || is_assoc3($arr3) || is_assoc3($arr4) || !is_assoc3($arr5)) {
echo 'error';
break;
}
}
$time[2] += microtime(true);
$time[3] -= microtime(true);
for ($i = 0; $i < 1000; $i++) {
if (is_assoc4($arr1) || is_assoc4($arr2) || is_assoc4($arr3) || is_assoc4($arr4) || !is_assoc4($arr5)) {
echo 'error';
break;
}
}
$time[3] += microtime(true);
$time[4] -= microtime(true);
for ($i = 0; $i < 1000; $i++) {
if (is_assoc5($arr1) || is_assoc5($arr2) || is_assoc5($arr3) || is_assoc5($arr4) || !is_assoc5($arr5)) {
echo 'error';
break;
}
}
$time[4] += microtime(true);
}
echo 'is_assoc1(): ' . $time[0] . "\n";
echo 'is_assoc2(): ' . $time[1] . "\n";
echo 'is_assoc3(): ' . $time[2] . "\n";
echo 'is_assoc4(): ' . $time[3] . "\n";
echo 'is_assoc5(): ' . $time[4] . "\n";
?>
is_assoc1() - 使用 unset(),速度有點慢,但記憶體使用率友好且沒有函式呼叫
is_assoc2() - 使用 isset(),速度最快,但只要陣列包含 NULL 就會返回 TRUE
is_assoc3() - 修復了 is_assoc2(),使用 array_key_exists(),速度快且記憶體使用率友好,並且比以下方法聰明得多(無需檢查所有這些鍵)
is_assoc4() - alex 的版本,具有適當的檢查和鍵排序
is_assoc5() - 修復了一點 JTS 的版本,真的很好,但使用了太多函式並檢查了所有鍵
結果
is_assoc1(): 2.1628699302673
is_assoc2(): 1.1079933643341
is_assoc3(): 1.7120850086212
is_assoc4(): 3.9194552898407
is_assoc5(): 1.9509885311127
在匿名發布的前一個範例中使用 empty() 將會導致「致命錯誤:無法在寫入內容中使用函式返回值」。我建議改用 count()
<?php
function is_assoc($array) {
return (is_array($array) && 0 !== count(array_diff_key($array, array_keys(array_keys($array)))));
}
?>
請注意,hperrin at gmail dot com 的基準測試結果在這段時間內已發生變化
is_array : 0.31888604164124
cast, === : 0.58448791503906
(使用 PHP 5.6.24,我預期使用 PHP 7 會有不同的結果)
下一個貼文不正確,因為它在空白陣列索引上存在問題
https://php.dev.org.tw/manual/es/function.is-array.php#89332
下一個程式碼使用上面連結的 php 程式碼
<?php
function is_assoc($var)
{
return is_array($var) && array_diff_key($var,array_keys(array_keys($var)));
}
function test($var)
{
echo is_assoc($var) ? "我是一個關聯陣列。\n" : "我不是一個關聯陣列。\n";
}
// 一個關聯陣列
$a = array("a"=>"aaa","b"=>1,"c"=>true);
test($a);
// 可能是關聯陣列?
$b = array(0 => "aaa", 1 => 1, 3 => true); // 索引 2 不存在
test($b);
?>
# 輸出
我是一個關聯陣列。
我是一個關聯陣列。
「關聯陣列是使用您指派的命名鍵的陣列。」
https://www.w3schools.com/php/php_arrays.asp
解決方案
<?php
function is_assoc(array $array)
{
return count(array_filter(array_keys($array), 'is_string')) > 0;
}
function test(array $array)
{
echo is_assoc($array) ? "I'm an assoc array.\n" : "I'm not an assoc array.\n";
}
// an assoc array
$a = array("a"=>"aaa","b"=>1,"c"=>true);
test($a);
// an array
$b = array(0=>"aaa",1=>1,3=>true);
test($b);
?>
# 輸出
我是一個關聯陣列。
我不是一個關聯陣列。
如果您想檢查純粹的關聯陣列,請將 > 0 替換為 === count($array)
將會檢查一個多維陣列到任何指定的層級。這是對 2005 年 11 月 16 日提交的修正,該修正會因為您必須為 foreach 提供一個陣列而失效。請注意,遞迴函數不應超過 100 層,否則可能會破壞伺服器上的記憶體堆疊。
<?php
// 遞迴檢查多維陣列到定義的深度層級
// 原始的 $level 必須是 2 或以上,否則會立即返回 true
function isDeepMultiArray($multiarray, $level = 2) { // 預設是簡單的多維陣列
if (is_array($multiarray)) { // 確認是陣列
if ($level == 1) { // $level 在指定數量的遞迴後達到 1
return true; // 返回 true 到遞迴函數條件式
} // 結束條件式
foreach ($multiarray as $array) { // 深入陣列一層
if (isDeepMultiArray($array, $level - 1)) { // 檢查子陣列
$message = "I'm a multiarray"; // 可選訊息
return $message; // 最好讓 $message = true,這樣函數會返回布林值
} // 結束遞迴函數
} // 結束迴圈
} else { // 在指定層級不是陣列
return false; // 也被遞迴使用,所以不能更改為訊息
}
}
if (isDeepMultiArray(array(array()), 2)); // 請注意,即使陣列為空,這也會返回 true
?>
BTW 我的符號與 PEAR 手冊中的編碼標準一致,這也是 php.net 建議遵循的。我希望這樣的函數能包含在 PHP6 中。