Неустановленный массив PHP в нескольких foreach

У меня есть массив, содержащий 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 добавит каждую подсеть и получит каждый их идентификатор. Второй foreach просканирует каждую подсеть и попытается найти дубликат (включая себя). Если это так, он должен добавить информацию об IP-адресе в массив, а затем отключить этот элемент, поскольку мы не хотим повторно вставлять подсеть в другой цикл.

Тем не менее, похоже, что это не отключает его правильно, поскольку в конце вставляются все подсети и IP-адреса (вставка всех подсетей приводит к большому количеству дубликатов).

Может ли кто-нибудь объяснить мне, почему сброс не работает правильно? Это потому, что я нахожусь в 2 уровне foreach?

Спасибо.


person Cocotton    schedule 28.06.2013    source источник
comment
Вы рассматривали возможность отмены этого порядка? сначала проверьте базу данных и добавляйте новые записи только в том случае, если совпадений не найдено? вместо добавления, затем проверки, затем удаления   -  person Dave    schedule 29.06.2013


Ответы (1)


Оператор foreach() в PHP тайно создает копию массива и повторяет эту копию. Это не оказывает никакого влияния на производительность, поскольку использует семантику копирования при записи, поэтому массив действительно копируется в память только в том случае, если вы выполняете запись в него внутри цикла foreach. Что ты здесь делаешь. Таким образом, ваши два цикла фактически перебирают 2 разные копии массива $subnets. Когда вы отключаетесь от одного массива, это никак не повлияет на другой.

Самый простой способ исправить это - указать PHP НЕ делать копию. Внесите это изменение в оба ваших цикла:

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

or

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

Тем не менее, я думаю, что ваш алгоритм здесь можно улучшить. Итак, похоже, что вы делаете:

  1. Повторить каждую подсеть
  2. Вставлять
  3. Запрос идентификатора вставленной строки
  4. Повторите массив и добавьте элемент в $ip_to_add, который включает идентификатор.

Мой вопрос: как вы хотите, чтобы $ip_to_add выглядел в конце? Кажется, прямо сейчас, если есть дубликаты, у вас будет только одна вставка в таблицу, но $ip_to_add будет иметь повторяющиеся строки? Кажется, что $ip_to_add будет иметь то же количество элементов, что и исходный массив $subnets? Это то, что вам нужно?

Если нет, то что бы я сделал:

  1. Дедупликация массива
  2. Повторите его, вставьте, используйте mysql_insert_id() чтобы получить идентификатор и добавить его в массив.
person Shane H    schedule 28.06.2013