PHP关联数组有序吗?

84

我来自Python背景,Python中类似的数据类型(字典)是一个无序的键值对集合。

我想知道PHP的关联数组是否无序?它们似乎是有序的。

$test = array(
  'test' => 'test',
  'bar' => 'bar',
);

var_dump($test);    

var_dump(array_slice($test, 0, 1));

测试始终先于bar,我可以像您看到的那样切割这个数组。那么这是否保证在不同的PHP版本中始终有序呢?顺序只是我声明数组时的顺序吗?因此,某些东西在内部将“test”指向数组中的[0]位置吗?我已经阅读了http://php.net/manual/en/language.types.array.php,但它并没有对这个问题提供太多解释。感谢您的回复。Ty


13
这些回答中有几个引用了PHP手册,其中指出数组是有序的。但这并没有完全回答原始问题。被询问的是默认顺序是什么!默认顺序似乎是按照元素分配的顺序,但文档在哪里说明我们可以从一个版本到另一个版本都依赖这种顺序? - flymike
6
我在 https://bugs.php.net/bug.php?id=76119 上提出了一个关于缺乏文档的问题,结果发现数组的顺序总是按添加键的顺序排列的(仅更改数组元素的值不会改变数组的顺序)。语言规范可以在 https://github.com/php/php-langspec/blob/master/spec/12-arrays.md 找到。 - Mikko Rantalainen
1
在Python3.6及以上版本中它们是有序的。 - Bob
5个回答

80
PHP关联数组(以及数值数组)是有序的,并且PHP提供了各种函数来处理数组键的排序,比如ksort()uksort()krsort()
此外,PHP允许您无序地声明带有数值键的数组。
$a = array(3 => 'three', 1 => 'one', 2 => 'two');
print_r($a);

Array
(
    [3] => three
    [1] => one
    [2] => two
)
// Sort into numeric order
ksort($a);
print_r($a);
Array
(
    [1] => one
    [2] => two
    [3] => three
)

从文档中可以看到:
PHP中的数组实际上是一个有序映射。映射是一种将值与键关联起来的类型。这种类型经过优化,可以用作数组、列表(向量)、哈希表(映射的一种实现)、字典、集合、栈、队列等多种用途。由于数组的值可以是其他数组,因此还可以创建树和多维数组。

12

文档说明如下:

An array in PHP is actually an ordered map.

是的,它们总是有序的。数组实现为一个哈希表


1
当然,我读了第一句话,但仍然感到困惑。我意识到,如果我有一个 $test = array('foo', 'bar'),它是按顺序排列的,$test[0] 是 foo,$test[1] 是 bar。但是当我有一个关联数组时,键不是按数字顺序排序的。$test['test'] 现在处于第一位置,但它不是按数字索引,而是通过字符串索引,这就是为什么我感到困惑并发布帖子的原因。 - dm03514
1
@dm03514,我不确定我理解你的意思。但是在 PHP 中,所有的数组都实际上是关联数组。希望这可以帮到你。 - alexn
@mikegreiling 同意,已更改。谢谢! - alexn

3

来自PHP手册

数组是有序的。可以使用各种排序函数更改顺序。有关更多信息,请参见数组函数部分。

我一直依赖它们有序的事实,在我参与的每个项目中都一直如此。


3
数组是有序的,但这并不意味着键被排序,而是它们以给定的顺序存在。精确定义的顺序未指定,但看起来它们是你在其中引入键值对的顺序。
想要理解这一点,可以想象一下如果没有被排序会意味着什么? 好比想到关系型数据库中的一个关系。 关系本身并非固有的有序:当你用查询操作访问它时,在你没有提供order子句的情况下,数据库可以按任何顺序返回相同的数据。 即使没有修改数据,也可能以不同的顺序返回相同的数据。

-1

这不是一个简单的问题。 在这种情况下,文档提供了开发中非常重要但不明显的点,例如:

$a = [0 => 'first', 1 => 'second', 3 => 'fourth'];
$a[2] = 'third';
foreach ($a as $element) print($element . "\n");

常识告诉我们,在迭代这个数组时,我们会看到“third”作为第三个元素,但事实并非如此:
first
second
fourth
third

因为元素是按照添加的顺序存储的,而0-1-2-3仅仅是一个键,而不是顺序。 通常文档假定数组的元素有某种顺序,并在文档中明确说明,这意味着你可以访问:第一个元素、n个元素和最后一个元素。但是直接操作它们并不是很清楚。也就是说,你可以得到最后一个元素,在末尾添加(push/pop),可以得到第一个元素 - shift,可以遍历它们(foreach),但不能直接获取第n个元素或将元素放置在某个特定位置而无需额外代码。 那么问题来了 - 如果由于某种原因需要依赖此顺序,我们该怎么办。


1
你分享的代码实际上并没有使用关联数组,而是使用了数字索引。 - Nico Haase
1
@NicoHaase 实际上它是可关联的。 - Your Common Sense
然而,这并不会使答案更好。我们是否可以访问关联数组的第n个元素是一个不同的问题(很多时候已经有了答案),这与“关联数组是否有序”无关。 - Your Common Sense
这个答案更多地涉及PHP数组中的排序。是的,我们可以选择第n个元素(例如切片),但存在一些逻辑问题,因此您必须记住:$a [2]与array_slice($a,2,1)不是同一个数组。键与顺序无关。 - Greenkey
如果 foreach ($yourarray as $key => $value) {/*...*/} 可以可靠地处理相同的键值对,即使 (3, 'fourth') 在 (2, 'third') 之前,那么该数组是有序的。你的观点涉及到数字索引决定顺序的假设,然而,顺序(正如你也指出的)是指元素添加到数组中的顺序。因此,PHP关联数组是有序的,尽管它们的数字索引不一定与其顺序一致。 - Lajos Arpad
当然!我明白了。我的评论是关于PHP中数组概念中的一个逻辑不一致性。 - Greenkey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接