0

我有一个包含 IP 地址及其各自子网信息的数组。第一次,我必须将子网信息添加到我的数据库中,但我试图这样做没有任何重复,使用此代码

#Note that this is pseudo-code
foreach ($subnets as $subnet)
{
    $query = 'INSERT INTO subnets (field1, field2) 
              VALUES ($subnet['subnet'], $subnet['netmask']);'

    $database->executeQuery($query);

    $query  = 'SELECT id FROM subnets 
               WHERE subnet = $subnet['subnet'] 
               AND mask = $subnet['netmask'];'
    $subnet_id = $database->getRow($query);

    foreach ($subnets as $key => $subnet_check)
    {
        if (($subnet['subnet'] == $subnet_check['subnet']) AND ($subnet['netmask'] == $subnet_check['netmask']))
        {
            $ip_to_add = array_merge($ip_to_add,array(array("subnet_id" => $subnet_id[0], "ip" => $subnet['ip'], "name" => $subnet['name'])));
            unset($subnets[$key]);
        }
    }
}

第一个 foreach 将添加每个子网并检索它们的每个 id。第二个 foreach 将扫描每个子网并尝试查找重复项(包括其自身)。如果是这样,它应该将 ip 地址信息添加到一个数组中,然后取消设置此元素,因为我们不想在另一个循环中重新插入子网。

然而,这似乎并没有正确地取消它,因为最后,每个子网和 IP 地址都被插入(插入所有子网会带来很多重复)。

谁能向我解释为什么 unset 不能正常工作?是因为我进入了2级foreach吗?

谢谢你。

4

1 回答 1

1

PHP 中的 foreach() 语句秘密地制作了数组的副本并迭代该副本。这不会对性能产生任何影响,因为它使用 Copy-on-Write 语义,因此只有在 foreach 循环内写入数组时,才会真正将数组复制到内存中。你在这里做什么。因此,您的两个循环实际上是在 $subnets 数组的 2 个不同副本上进行迭代。当您从一个阵列取消设置时,这不会对另一个阵列产生任何影响。

解决此问题的最简单方法是指示 PHP 不进行复制。在两个循环中进行此更改:

foreach(array() as &$row) {} 

或者

foreach(array() as $key => &$row) {}

也就是说,我确实认为您的算法可以改进。所以看起来你正在做的是:

  1. 迭代每个子网
  2. 插入
  3. 查询插入行的ID
  4. 重新迭代数组并将包含 ID 的项目添加到 $ip_to_add。

我的问题是,您希望 $ip_to_add 最终看起来像什么?现在看来,如果有重复项,您只会在表中插入一个,但 $ip_to_add 会有重复的行?似乎 $ip_to_add 将具有与原始 $subnets 数组相同数量的项目?那是你需要的吗?

如果没有,我会做的是:

  1. 对数组进行重复数据删除
  2. 迭代它,插入它,使用mysql_insert_id()获取 ID,并将其添加到数组中。
于 2013-06-28T22:51:14.013 回答