请注意,“强制转换为数组”检查已过时。
在 PHP 5.6 上运行该代码会导致以下结果
is_array : 0.93975400924683
强制转换,=== : 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
强制转换,=== : 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) ? "我是一个关联数组。\n" : "我不是一个关联数组。\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
强制转换,=== : 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 进行比较,因此将回调中的三元运算符 else 返回为 -1)。
我找到了一个更快的确定数组的方法。如果您使用 is_array() 数百万次,您会注意到一个*巨大的*差异。在我的机器上,这种方法大约是使用 is_array() 的时间的 1/4。
将值强制转换为数组,然后检查(使用 ===)它是否与原值相同。
<?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;
// Set this now so the first for loop doesn't do the extra work.
$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 "\nTested $count iterations."
?>
</pre>
输出结果类似
什么方法更快地确定数组?
is_array : 7.9920151233673
cast, === : 1.8978719711304
测试了 1000000 次迭代。
alex frase 的例子很快,但 elanthis at awesomeplay dot com 的例子更快,而 Ilgar 对 alex 代码的修改是有错误的(“ || $_array[$k] !== $v” 部分)。此外,我认为 Ilgar 建议在变量不是数组时返回假值并不适合,我认为在代码运行之前检查数组是否为空也是一个合适的检查。
所以这是修改后的 (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's 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
以下是修正后的版本(只有两行不同)
<?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 和内存密集型”函数调用之前停止。
最终,在一个比率为 3 个非空数组对 1 个空数组的情况下,为 1000000 次迭代计算的结果是,它需要少 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.net/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) ? "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(0 => "aaa", 1 => 1, 3 => true); // 索引 2 不存在
test($b);
?>
# 输出
我是一个关联数组。
我是一个关联数组。
"关联数组是指使用命名键的数组,这些键是由你分配给它们的。"
https://w3schools.org.cn/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";
}
// 一个关联数组
$a = array("a"=>"aaa","b"=>1,"c"=>true);
test($a);
// 一个数组
$b = array(0=>"aaa",1=>1,3=>true);
test($b);
?>
# 输出
我是一个关联数组。
我不是一个关联数组。
如果你想检查纯关联数组,将 > 0 替换为 === count($array)
将检查多维数组到任何指定的级别。这是对 11/16/05 提交的修复,它会中断,因为你必须为 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
?>
顺便说一句,我的符号与 PEAR 手册的编码标准一致,这也是 php.net 建议遵循的标准。我希望这样的函数能够包含在 PHP6 中。