ФорумПрограммированиеPHP для идиотов → Профи обосрались :) Загадка с массивами

Профи обосрались :) Загадка с массивами

  • ivanscm

    Сообщения: 1251 Репутация: N Группа: Джедаи

    Spritz 4 марта 2011 г. 9:54


    php > $a = array(1,2,3,4,5);
    php > foreach ($a as $k => &$v) $a[$k] = $v;
    php > print_r($a);
    Array
    (
       [0] => 1
       [1] => 2
       [2] => 3
       [3] => 4
       [4] => 5
    )
    php > foreach ($a as $k => $v) $a[$k] = $v;
    php > print_r($a);
    Array
    (
       [0] => 1
       [1] => 2
       [2] => 3
       [3] => 4
       [4] => 4
    )


    Почему? Это баг PHP или кривые руки?
    С возвращением, Пiха! hyperoff.ru - качественный хостинг php
  • master

    Сообщения: 3244 Репутация: N Группа: Джедаи

    Spritz 4 марта 2011 г. 10:21, спустя 26 минут 46 секунд

    после цикла нужно делать unset($v)
    не всё полезно, что в swap полезло
  • master

    Сообщения: 3244 Репутация: N Группа: Джедаи

    Spritz 4 марта 2011 г. 10:35, спустя 13 минут 25 секунд

    Я лично отношу это к багам, хотя возможно где-то в доках есть описание такого поведения.
    Ещё один повод не любить пхп.
    не всё полезно, что в swap полезло
  • Timur

    Сообщения: 1068 Репутация: N Группа: Джедаи

    Spritz 4 марта 2011 г. 10:37, спустя 2 минуты 40 секунд

    При использовании ссылок в foreach в последнем элементе остается именно ссылка на переменную $v. Перебирая массив второй раз и используя туже ссылку мы поочередно присваиваем ей значения элементов ([tt]$a as $k => $v[/tt], где $v на самом деле ссылка на тоже значение, что и $a[4]). Поэтому значение $a[4] тоже меняется, и к последней итерации второго цикла оно равно 4 и ей снова присваивается 4.

    Короче посмотри на вывод кода:
    <?php
    $a = array(1,2,3,4,5);
    foreach ($a as $k => &$v) {
    $a[$k] = $v;
    var_dump($a);
    }
    print "<hr>";
    foreach ($a as $k => $v) {
    $a[$k] = $v;
    var_dump($a);
    }


    Это неочевидное, но документированное поведение - в мане к  foreach написано:
    Warning
    Reference of a $value and the last array element remain even after the foreach loop. It is recommended to destroy it by unset().


    Т.е. нужно просто после второго цикла сделать unset($v).
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 4 марта 2011 г. 10:48, спустя 11 минут 3 секунды

    я наступал на эти грабли )))
    ιιlllιlllι унц-унц
  • Timur

    Сообщения: 1068 Репутация: N Группа: Джедаи

    Spritz 4 марта 2011 г. 11:54, спустя 1 час 5 минут 29 секунд

    Я лично отношу это к багам



    #include <stdio.h>

    int main(void) {
    int a[] = { 1, 2, 3, 4, 5 };

    int* v;
    int i;

    for (i = 0; i < 5; ++i) {
    v =& a;
    a = *v;
    printf("%d ", a);
    }
    printf("\n");

    for (i = 0; i < 5; ++i) {
    *v = a;
    a = *v;
    printf("%d ", a);
    }
    printf("\n");

    return 0;
    }


    Вывод:
    1 2 3 4 5
    1 2 3 4 4

    Баг?
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 4 марта 2011 г. 12:07, спустя 13 минут 13 секунд


    Т.е. нужно просто после второго цикла сделать unset($v).


    после первого цикла ))
    ιιlllιlllι унц-унц
  • Абырвалг

    Сообщения: 6480 Репутация: N Группа: Джедаи

    Spritz 4 марта 2011 г. 12:08, спустя 1 минуту 16 секунд


    я наступал на эти грабли )))


    ха! я за 2 года программинга ни разу не наступал, а вот на прошлой неделе тоже наступил
    Спустя 32 сек.
    но не придал этому значения, просто во 2 цикле сделал тоже &. А тут вот оно как
  • master

    Сообщения: 3244 Репутация: N Группа: Джедаи

    Spritz 4 марта 2011 г. 12:30, спустя 21 минуту 22 секунды

    Timur, не сравнивай жопу с пальцем. В сишном коде явно видно что в первом цикле указатель меняет адрес, а во втором - не меняет. В пхпшном коде нихуя не видно, значит переменная должна разыменовываться автоматически.


    a = {0=>1,1=>2,2=>3,3=>4,4=>5}

    a = a.each{|k,v| a[k]}

    print a // {0=>1,1=>2,2=>3,3=>4,4=>5}

    a = a.each{|k,v| a[k]}

    print a // {0=>1,1=>2,2=>3,3=>4,4=>5}
    не всё полезно, что в swap полезло
  • vasa_c

    Сообщения: 3131 Репутация: N Группа: в ухо

    Spritz 4 марта 2011 г. 13:52, спустя 1 час 22 минуты 50 секунд

    на основании чего переменная что-то должна?
  • master

    Сообщения: 3244 Репутация: N Группа: Джедаи

    Spritz 4 марта 2011 г. 14:20, спустя 27 минут 41 секунду

    на основании чего переменная что-то должна?

    на основе профессиональной этики
    не всё полезно, что в swap полезло
  • Timur

    Сообщения: 1068 Репутация: N Группа: Джедаи

    Spritz 4 марта 2011 г. 18:19, спустя 3 часа 58 минут 43 секунды

    В сишном коде явно видно что в первом цикле указатель меняет адрес, а во втором - не меняет.

    В пхп-шном это тоже видно (хоть и так ясно, согласен), что в первом цикле $v используется в качестве ссылки, а во втором - в качестве значения.
    Вопрос - должна или не должна обнуляться ссылка? - спорный и вот почему.

    foreach ($a as $k => $v) {}
    по окончании цикла $v будет равно последнему элементу.

    foreach ($a as $k => &$v) {}
    Тогда вполне логично, что после такого цикла $v будет ссылкой на последний элемент. Почему же она должна автоматически ансетиться?

    В сишном коде, явным образом описано то же, что делает пхп (упрощенно, конечно). C Ruby, к сожаленью не знаком, но вижу в коде два идентичных цикла, в то время как в примере на PHP они разные. Вообще в Ruby разве есть ссылки?

    В Perl, например, они есть, но там вопрос решен - переменная-итератор локализуется в цикле.
    #!/usr/bin/perl

    my $v = 6789;
    my @a = (1,2,3,4,5);
    for $v(@a) { # $i - ссылка
    }
    print $v; # выведет 6789

    Если бы переменная $v не была объявлена ранее, то ничего бы не вывел. Ну считай, да, как если бы она обнулялась.

    Короче, это всё я к чему. Выстрелить себе в ногу можно разными способами. Главное, чтобы эти способы были описаны в мануале :)
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 4 марта 2011 г. 18:19, спустя 23 часа 59 минут 51 секунду

    переменная срет на этику, она выше добра и зла.
    к указателям всегда надо относиться с осторожностью, всего то делов.
    ιιlllιlllι унц-унц
  • shuranov

    Сообщения: 113 Репутация: N Группа: Кто попало

    Spritz 28 апреля 2011 г. 16:35, спустя 54 дня 21 час 15 минут

    var_dump и не ипет :)
  • ivanscm

    Сообщения: 1251 Репутация: N Группа: Джедаи

    Spritz 28 апреля 2011 г. 18:27, спустя 1 час 52 минуты 31 секунду

    shuranov, некропостер :)
    С возвращением, Пiха! hyperoff.ru - качественный хостинг php

Пожалуйста, авторизуйтесь, чтобы написать комментарий!