【问题标题】:How far can multidimensional arrays go in PHP?多维数组在 PHP 中能走多远?
【发布时间】:2014-10-17 13:06:15
【问题描述】:

我知道这样的数组中可以有一个数组。

Array01 (

[0] => Array
    (
        [0] => 40292633
        [1] => 412
    )

[1] => Array
    (
        [0] => 41785603
        [1] => 382
    )

[2] => Array
    (
        [0] => 48792980
        [1] => 373
    )

[3] => Array
    (
        [0] => 44741143
        [1] => 329
    )
)

这样的数组中的数组可以有数组吗?

Array01 (

[0] => Array
    (
       [0] => Array
       (
           [0] => 40292633
           [1] => 412
       )

        [1] => Array
       (
           [0] => 41785603
           [1] => 382
       )
    )

[1] => Array
    (
        [0] => 41785603
        [1] => 382
    )

[2] => Array
    (
        [0] => 48792980
        [1] => 373
    )

[3] => Array
    (
        [0] => 44741143
        [1] => 329
    )
)

我很好奇的是这能走多远,一个数组可以有多少个数组?

【问题讨论】:

  • 使用google Luke
  • 在遥远的土地上......
  • @RiggsFolly 他问的是他们能得到多深,而不是他们能包含多少记录。
  • 您受到时间限制(php 脚本可以 有有限的可用执行时间)、已安装操作系统支持的最大整数大小和可用 RAM。 PHP 没有内置技术限制,即“您不能拥有超过 1000 个维度”。在内部,它是一个哈希表(我们都知道),它转换为始终只有 1 个维度的东西(缺乏更好的描述)。话虽如此,@EliasVanOotegem 所说的是正确的——保持理智。
  • @sectus - 我真的不想就琐碎的事情再进行一场毫无意义的辩论。我认为存在语言障碍,并且您不太了解我写的内容。无论如何,我不是来讨论你是否正确或我是否正确,所以如果我们能避免我们相互“解释”事情的讨论,我将不胜感激。要点是,在处理 PHP 数组时,必须对它们创建的维数保持清醒。深入 1000(甚至 50)的深度是疯狂的,这就是我想要强调的。

标签: php arrays multidimensional-array


【解决方案1】:

你可以无限深入。

编辑:

每个数组的元素数量有限制,如here 所述,但这是与深度不同的问题。

当然,您需要考虑机器的限制(时间和 RAM),但 PHP 没有理论上的限制或限制,可以无限深入。

【讨论】:

  • 为什么要投反对票?您可以无限深入,这与每个数组的最大大小不同。
  • 虽然理论上不正确(如重复答案中所解释的那样),但对于大多数计算机而言,它在物理上是正确的(出于这个原因,我投了赞成票,但您的答案只对了一半)。
  • 理论上不正确是什么意思?重复是关于一个数组的元素数量,如果你无限深,每个数组将包含一个数组,所以这个限制永远不会达到。
  • 你可以加上'and long time limit',因为创建这样的数组需要时间。
【解决方案2】:

好的,让我们计算可能的最大值。我们需要什么?

  • 我们需要知道 PHP 需要多少内存来存储/创建一个数组
  • 我们需要知道我们可以使用多少内存(最佳情况)
  • 将内存量除以存储 PHP 数组所需的内存量

PHP 数组有多大?嗯,这很容易解决:PHP 是开源的,知道数组实际上是哈希表,让我们看看 PHP 需要的所有点点滴滴:

typedef struct bucket {
    unsigned long h;
    unsigned int nKeyLength;
    void *pData;
    void *pDataPtr;
    struct bucket *pListNext;
    struct bucket *pListLast;
    struct bucket *pNext;
    struct bucket *pLast;
    const char *arKey;
} Bucket;

typedef struct _hashtable {
    unsigned int nTableSize;
    unsigned int nTableMask;
    unsigned int nNumOfElements;
    unsigned long nNextFreeElement;
    Bucket *pInternalPointer;
    Bucket *pListHead;
    Bucket *pListTail;
    Bucket **arBuckets;
    void * pDestructor;
    short persistent;
    unsigned char nApplyCount;
    short bApplyProtection;
} HashTable;

typedef union _zvalue_value {
 long lval;
 double dval;
 struct {
  char *val;
  int len;
 } str;
 HashTable *ht;//HashTable, this is used for arrays
 void* obj; //is actually a zend_object, but I believe that's a typedef to a pointer
} zvalue_value;


typedef struct _zval_struct {
 zvalue_value value;
 unsigned int refcount__gc;
 unsigned char type;
 unsigned char is_ref__gc;
} zval;

现在,让我们快速了解一下它使用了多少字节:

int main(void)
{
    printf(
        "%zu bytes where pointers are %zu bytes in size\n",
        sizeof(Bucket) + sizeof(zval) + sizeof(HashTable),
        sizeof(void *)//sizeof pointer
    );
    return 0;
}

现在在典型的 32 位系统上,这告诉我们所有结构的总大小为 96 字节,而指针为 4 字节大。要使用数组,按理说我们需要一个指向它的指针,所以一个数组至少需要 100 个字节(96 个字节 + 4 个字节用于指向数组的指针)。这告诉我们什么?好吧,如果一个指针占用 4 个字节,那么我们就知道有多少个不同的指针:2^(4*8) => 2^32,这使我们最多可以寻址 4294967296 个字节。当然单个指针用了32个字节,所以我们可以定义的指针总数其实是2^2/32,也就是134217728
同样,要知道这个内存量可以存储多少个 PHP 数组,我们需要 2^32/100,这给了我们 42949672.96 个数组,但是 0.96 不是一个数组(这还不够),所以我们不能使用那个位.理论上,42 949 672 是我们可以创建的最大数组数量。

注意:64 位机器上的输出不是只是 32 位机器的两倍,它是 “168 字节,其中指针是 8 字节”。如果您想知道 64 位平台上的最大数组数量是多少,请进行数学运算 (2^64/174)...

这是准确的吗?不,绝对不是。我根本没有考虑其他开销,但可以肯定地说,如果你想疯狂地创建一个 100 维数组,你可以创建。然而,访问一个值确实意味着大量的间接、哈希表查找,因此,这将导致相当大的性能开销,所以 KISS(即保持简单和理智)。

【讨论】:

    【解决方案3】:

    您在第一个示例中描述的是一个“简单的”二维数组 - 一个“数组的数组” - 您必须在其中使用两个索引来访问所需的数据。

    在第二个示例中,您描述了一个混合维数组 - 对于要访问的某些元素,您需要提供三个索引,而对于其他元素,只需提供两个。

    AFAIK,数组的大小(以及与此相关的任何其他变量)仅受 PHP 解释器可用的内存(以及内存中已经存在的其他变量)的限制。

    更新:澄清

    PHP 中的设计对数组深度/维度没有硬性限制。您可以拥有任意多个维度,前提是:

    1. 您没有达到内存限制
    2. 您的数组之一没有超过 PHP 的元素限制^

    ^数组可以包含的元素数量是有限制的 - 如果您有兴趣,RiggsFolly 提供了指向该特定主题的this answer 的链接。

    【讨论】:

    • 一个数组的大小被限制为 C 类型 unsigned int 的大小,它(由 C 标准定义为 至少 2 个字节的大小,但通常实现为 4 个字节),因此绝对安全,数组不能大于 2^16 -1,但通常限制为 2^32 -1
    • 伙计们,我们这里不是在讨论数组大小,而是在讨论数组的深度。
    • @DanyCaissy:我知道,但这个答案的最后一句话是完全错误的:“数组的大小仅受可用内存的限制”。此答案中未讨论维度的数量以及对维度的限制。我同意你的观点:我不相信有限制
    • 已更新。 @DanyCaissy:你有我的赞成票,对于那条线。
    【解决方案4】:

    你可以自己测试一下

    <?php
    $i =0;
    $array = [];
    $a = &$array;
    while(true) {
    $a = &$a[];
    $i++;
    if ($i % 1000000==0){ echo $i,' ';};
    }
    

    【讨论】:

    • 这不是创建无限深的数组,而是创建循环引用,不是一回事...
    • @EliasVanOotegem,尝试在一些迭代后输出 $array。
    • 对不起,有些混乱,但我会写while(true) { $a[] = []; $a = &amp;$a[0];}(添加一个新数组,引用最后一个数组)
    • @EliasVanOotegem,您显然不必创建数组和数组元素。 = &amp;$a[]创建$a(如果不存在),将$a转换为数组,创建数组的项,新项的值为null。
    • 我知道,但我更喜欢明确
    猜你喜欢
    • 2011-01-20
    • 1970-01-01
    • 1970-01-01
    • 2023-03-11
    • 2010-09-05
    • 2019-12-13
    • 2013-03-06
    • 1970-01-01
    • 2017-09-02
    相关资源
    最近更新 更多