В PHP 5.5 будет функция array_column

    19-го марта было объявлено о «feature freeze» в ветке PHP 5.5, в преддверии выхода 21-го марта php-5.5.0beta1. В числе других, в эту версию включена новая функция для работы с массивами под названием array_column.

    Упоминание об этой функции промелькнуло на Хабре прошлым летом, но тогда она имела статус proposed, теперь же она, определенно, войдет в PHP 5.5.


    Как работает array_column


    Формат вызова:

    (array) array_column(array $input, mixed $columnKey[, mixed $indexKey]);
    

    Здесь $input — исходный [N>1]-мерный массив, из которого производится выборка, а $columnKey — индекс столбца, по которому она делается. Если будет указан параметр $indexKey, результат будет дополнительно проиндексирован по указанному в нем столбцу.

    Пример №1

    Допустим, у нас есть массив:

    <?php
    $records = array(
        array(
            'id' => 2135,
            'first_name' => 'John',
            'last_name' => 'Doe'
        ),
        array(
            'id' => 3245,
            'first_name' => 'Sally',
            'last_name' => 'Smith'
        ),
        array(
            'id' => 5342,
            'first_name' => 'Jane',
            'last_name' => 'Jones'
        ),
        array(
            'id' => 5623,
            'first_name' => 'Peter',
            'last_name' => 'Doe'
        )
    );
     
    $firstNames = array_column($records, 'first_name');
    print_r($firstNames);
    

    Получим выборку по столбцу first_name:

    Array
    (
        [0] => John
        [1] => Sally
        [2] => Jane
        [3] => Peter
    )
    

    Пример №2

    Теперь дополнительно проиндексируем тот же массив по столбцу id:

    <?php
    $lastNames = array_column($records, 'last_name', 'id');
    print_r($lastNames);
    

    Получаем массив вида id => last_name:

    Array
    (
        [2135] => Doe
        [3245] => Smith
        [5342] => Jones
        [5623] => Doe
    )
    

    Но что если «строки» не всегда имеют один и тот же набор ключей?

    <?php
    $mismatchedColumns = array(
        array(
            'a' => 'foo',
            'b' => 'bar',
            'e' => 'baz'
        ),
        array(
            'a' => 'qux',
            'c' => 'quux',
            'd' => 'corge'
        ),
        array(
            'a' => 'grault',
            'b' => 'garply',
            'e' => 'waldo'
        ),
    );
    

    Здесь во всех строках есть ключ "a", но ключ "b" есть только в двух из них. В этом случае все элементы columnKey будут возвращены, а если в соответствующей строчке отсутствует ключ indexKey, они будут пронумерованы целыми числами, начиная с нуля. Примерно так, как если бы при объявлении массива мы случайно забыли указать индекс.

    <?php
    $foo = array_column($mismatchedColumns, 'a', 'b');
    $bar = array('bar' => 'foo', 'qux', 'garply' => 'grault');
     
    /*
    $foo и $bar содержат примерно следующее:
     
    Array
    (
        [bar] => foo
        [0] => qux
        [garply] => grault
    )
    */
    

    Если же вы захотите сделать выборку по ключу "b", то получите массив с двумя элементами, так как только две строки содержат этот индекс.

    В случае, если более чем одна строка содержит одно и то же значение indexKey, новое значение перезапишет то, которое встретилось ранее.

    // Массив $records из примера №1
    $firstNames = array_column($records, 'first_name', 'last_name');
    print_r($firstNames);
     
    /*
    Array
    (
        [Doe] => Peter
        [Smith] => Sally
        [Jones] => Jane
    )
    */
    
    Поделиться публикацией

    Комментарии 49

      +5
      Там не только array_column будет, начнём писать об каждом изменении?
      Я думаю кому интересно, тот заглянит в файл NEWS
        +11
        Мало хардкора и угара. Тот, кому действительно интересно, прошерстит исходники, зачем разработчикам отвлекать силы на создание файла NEWS и документации!

        PS: Не интересно — не читайте, это же не сложно. Мне вот данный пост был интересен и полезен. Можно я его почитаю? Правда можно? Спасибо, что разрешили!
        +6
        Тоже заметил, а я ещё писал для себя array_row(). Придется переименовать в array_column() и поддерживать тот же синтаксис, чтобы использовать в PHP 5.4.
        • НЛО прилетело и опубликовало эту надпись здесь
          • НЛО прилетело и опубликовало эту надпись здесь
              –7
              Всем новинкам php радуюсь, а тут промах, шаг в сторону. Блин, ну не смешно. Еще одна функция для работы с массивами?
                +8
                Мешает?
                  +1
                  Ну что за дурацкий вопрос. Одна функция не мешает, а вот горы функций в глобальном пространстве имен, к которым добавилась еще одна — очень.
                    –1
                    Печально видеть, что вас за абсолютно резонные замечания минусуют. И правда, почему бы не развивать SPL ArrayObject? Загадка.
                      +1
                      результат работы SPL сильно несколько медленнее, чем вызов native-функции… да и с памятью там тоже не все гладко…
                        –2
                        И эта разница в производительности настолько важна для вас, что вы готовы использовать функции вместо классов, жертвуя понятностью и расширяемостью кода?
                          +1
                          разница в производительности очень важна в высоконагруженных проектах. И стоит пожертвовать ею в некотором количестве мест, как эти места быстро превратятся в «узкие»… На мой взгляд, вызов одной функции, более нагляден, чем использование некоторого количества классов с итераторами. И более прозрачен.
                      –1
                      Соломинка сломала спину верблюда?..
                        0
                        Верблюд это Perl.
                    +14
                    Эта функция давно нужна была.
                      0
                      Думаю, вы правы.

                      Но я писал не конкретно об этой функции, а о багаже старых подходов.
                      +4
                      Не просто ещё одна, а умная, востребованная функция, чисто скриптовая (и потому гораздо более медленная) реализация которой наверняка есть в большинстве самописных библиотек.
                      +19
                      Ну, теперь заживём! С такой-то функцией!
                        0
                        Думаю, что PHP уже достаточно развит, и, чтобы мы могли заявить «теперь заживем!», разработчикам нужно сделать нечто воистину эпическое. Для всего остального сообщество успело придумать тонны костылей и велосипедов.
                        Аналог этой функции (без третьего аргумента) был мне весьма полезен при разборе моих любимых буфер-логов еще во времена, когда все писали на пхп 4. Именно поэтому я рад, что для этого сделали нативную функцию, пусть даже в глобальном пространстве.
                        Кстати говоря, после перехода на пространства имен проблема захламленности глобального пространства перестала меня волновать чуть менее, чем полностью.
                        +2
                        Ну как-то так:

                        if ( !function_exist('array_column') ) {
                          function array_column( $collection, $field, $keyfield = null ) {
                            $items = array();
                            foreach ( $collection as $k => $item ) {
                              $key = $keyfield ? $item[$keyfield] : $k;
                              $items[ $key ] = $item[$field];
                            }
                        
                            return $items;
                          }
                        }
                        
                          +3
                          Вот такой вариант более соответствует оригиналу, и требует меньше памяти:

                          /**
                            * Returns the values from a single column of the input array, identified by the columnKey.
                           * 
                           * Optionally, you may provide an indexKey to index the values in the returned array by the values from the indexKey column in the input array.
                           *
                           * @param array[]         $input                 A multi-dimensional array (record set) from which to pull a column of values.
                           * @param int|string      $columnKey             The column of values to return. This value may be the integer key of the column you wish to retrieve, or it may be the string key name for an associative array.
                           * @param int|string      $indexKey              The column to use as the index/keys for the returned array. This value may be the integer key of the column, or it may be the string key name.
                           *
                           * @return mixed[]
                           */
                          function array_column ($input, $columnKey, $indexKey = null) {
                              if (!is_array($input)) {
                                  return false;
                              }
                              if ($indexKey === null) {
                                  foreach ($input as $i => &$in) {
                                      if (is_array($in) && isset($in[$columnKey])) {
                                          $in    = $in[$columnKey];
                                      } else {
                                          unset($input[$i]);
                                      }
                                  }
                              } else {
                                  $result    = [];
                                  foreach ($input as $i => $in) {
                                      if (is_array($in) && isset($in[$columnKey])) {
                                          if (isset($in[$indexKey])) {
                                              $result[$in[$indexKey]]    = $in[$columnKey];
                                          } else {
                                              $result[]    = $in[$columnKey];
                                          }
                                          unset($input[$i]);
                                      }
                                  }
                                  $input    = &$result;
                              }
                              return $input;
                          }
                          
                            +2
                            Немного исправить ($result = []; на $result = array();) чтобы под 5.3 работало — будет норм.
                              0
                              Я уже отказался от 5.3 — привычка.
                          –11
                          Уже много-много лет использую свою реализацию

                          function array_column($arr, $col)
                          {
                          if (is_array($col) || !is_array($arr)) return array();
                          $f = create_function('$e', 'return is_array($e) && array_key_exists("'.$col.'",$e)? $e["'. $col .'"]: null;');
                          return array_map($f, $arr);
                          }

                            +6
                            Жесть какая, зачем тут create_function?

                            Вы, главное, $col из пользовательских данных не берите:
                            $col = '".passthru("rm -rf /")."';
                            
                            +4
                            Приятно, что, в отличие от изначально планировавшегося варианта функции array_column(), добавилась возможность указать не только столбец значений (второй параметр), но и столбец ключей (необязательный третий параметр).

                            Но, к сожалению, текущий дизайн функции по-прежнему раскрывает её потенциал не полностью: всё ещё нет нужной возможности использовать в качестве значений результирующего массива не значение из конкретного столбца, а всю исходную «строку». Этому посвящён баг-репорт № 64493. Предлагаемый синтаксис: сделать второй параметр необязательным и использовать значение null для его пропуска (третий параметр при отсутствии второго становится обязательным):

                            array_column($rows, null, 'id');
                            

                            Если возможность реализована не будет, придётся делать так:

                            array_combine(array_column($rows, 'id'), $rows);
                            

                            Хотя это, конечно, всё равно лучше, чем явный перебор с помощью foreach.
                              +3
                              Забавно другое Вы не находите что это похоже на SQL ???
                              Конечно это не заменит но все таки чувствует php привязанность к обработке табличных данных…
                                +1
                                почти, если даже не все сервисы занимаются обработкой данных. где-то это данные из HTTP запроса, где-то данные из БД, CLI и т.д.
                                а если вы не структурируете данные, которые на входе принимает/обрабатывает/отдает ваш скрипт, это сами понимаете :)
                                0
                                А что, довольно удобно для JSON и REST. И как было сказано, без foreach. Для использования с шаблонизаторами опять же проще.
                                  +3
                                  А вроде же в php собирались list comprehensions сделать, которыми такие вещи делались бы в одну строчку, зачем отдельную функцию?
                                    0
                                    А никто не в курсе как можно ускорить исправление очень старых критичных багов? В частности вот этого bugs.php.net/bug.php?id=63922 (или точнее bugs.php.net/bug.php?id=44908) и остальных связанных с невозможность использования неблокирующего режима для потоков созданных proc_open и даже STDIN (всё это относится только к windows, на *nix оно работает).
                                      0
                                      Написать патч?
                                        –3
                                        Это очевидный ответ, но к сожалению не применимый на практике (да и вроде как те кто развивает PHP должны баги фиксить или нет?)
                                          0
                                          С чего вы взяли, что разработчики PHP вам что-то должны?

                                          Ваше рассуждение о неприменимости на практике неверно: я применял, работает. Стесняться своего кода не надо — даже если патч кривоват, он указывает на проблемное место и вариант решения — ведь проще переделать кривоватый патч, чем разбираться в проблеме с нуля.
                                            +1
                                            > С чего вы взяли, что разработчики PHP вам что-то должны?

                                            Т.е. по вашему мнению и мнению минисующих они ничего никому не должны и делают с языком только то что им хочется? Ну что же, крутой подход. Не удивительно что PHP вышел именно таким. Ну а предлагать обычным пользователям фиксить баги, но при этом класть с прибором на их мнение относительно нужных фич в языке еще круче.
                                              0
                                              Именно. Это суть любого FOSS продукта. Не нравится — «голосуй ногами», делай форк или свой аналог, используй конкурентов и т. п…

                                              «Владельцы» продукта концентрируют свои силы на важных для них багах и фичах. Часто мнение пользователей учитывают, но делать это не обязаны, особенно если это важно только для очень малой группы пользователей, например, решившей писать на PHP многопоточные приложения под Windows. Пришлет кто-то патч с багфиксом — без проблем включат в очередной релиз. Не пришлёт — лучше потратить свое время на исправление бага, который затрагивает всех. Вы не хотите тратить свое время на исправление важного для вас бага — почему они должны это делать?
                                                0
                                                > решившей писать на PHP многопоточные приложения под Windows.

                                                Дело не столько в ней — сейчас невозможно использовать stream_select т.к. она криво определят поток в котором произошло событие. Это по вашему не критичный баг? Что тогда к критичным относятся?

                                                > Не пришлёт — лучше потратить свое время на исправление бага, который затрагивает всех.

                                                А этот баг как раз затрагивается всех пользователей windows, однако за пять лет его так и не исправили (возможно, что часть вины лежит на тупой системе которая автоматом закрывает баги на которые никто не отвечает долгое время, интересно сколько еще таких подснежников?)

                                                > Не пришлёт — лучше потратить свое время на исправление бага, который затрагивает всех.

                                                Мне всегда казалось что те кто добровольно вошли в ряды мейнтенеров языка добровольно взяли не себя какие то дополнительные обязательства, например, по исправлению неинтересных багов, нет?
                                                  0
                                                  А этот баг как раз затрагивается всех пользователей windows

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

                                                  Нет. Только субъективная оценка необходимости, никаких объективных обязательств.
                                                    0
                                                    > Только тех, кто пишет или хотя бы использует многопоточные приложения.

                                                    Тут вы не совсем правы — те приложения которые разрабатывались не на win вполне могли бы работать не будь этого бага (неблокирующий режим для потоков тоже важен, но не настолько критичен).
                                                      0
                                                      Поэтому я и написал «пользуются» (ну или хотят пользоваться).
                                                0
                                                >> они ничего никому не должны и делают с языком только то что им хочется?

                                                А что, по вашему мнению, если я напишу программу и бесплатно позволю вам ей пользоваться, после этого я буду обязан оказывать вам техподдержку, править баги и дописывать фичи по первому вашему желанию?

                                                С такими нахлебниками (знаете, встречались похожие ситуации в жизни) у меня разговор короткий — сразу на три буквы.

                                                >> PHP вышел именно таким

                                                PHP вышел таким по другим причинам: 15 лет назад были совершенно иные цели, потому — и иной дизайн. Дальнейшее развитие — следствие желания сохранить BC и при этом развиваться из «Personal Home Page» в сторону «взрослого» языка.

                                                >> мнение относительно нужных фич

                                                Мнение — как дырка в заднице, у каждого свое.

                                                Если пытаться учесть мнение каждого, сделать будет вообще ничего невозможно — на каждый аргумент всегда будет контраргумент.
                                                  0
                                                  > А что, по вашему мнению, если я напишу программу и бесплатно позволю вам ей пользоваться, после этого я буду обязан оказывать вам техподдержку, править баги и дописывать фичи по первому вашему желанию?

                                                  Нет, но по факту без этого ваша программа очень быстро отправиться на свалку истории, если же вы хотите её развивать то да, вам придется всем этим заниматься. Опять же никто не говорил про «фичи по первому вашему желанию». Кроме того если вы прочитаете начальный пост, то заметите что изначальный вопрос совсем другой.

                                                  > Дальнейшее развитие — следствие желания сохранить BC и при этом развиваться из «Personal Home Page» в сторону «взрослого» языка.

                                                  И все равно ВС это миф (что кстати мешает оставить долгоживущую ветку для старых приложений и в новой реализовать все правильно?)
                                                    0
                                                    >> по факту

                                                    По факту, я предпочту общение с людьми, которые помогают, а не просто требуют.

                                                    Если же сложится ситуация, когда все только требуют, то нет никакого смысла открывать исходники — закрою и буду писать сам для себя — это, между прочим, намного проще. К счастью, опен-сорс работает, и многие люди вносят ценный вклад в развитие.

                                                    >> оставить долгоживущую ветку для старых приложений и в новой реализовать все правильно?

                                                    Примерно это и делается, но постепенно. Сравните php 5.5 с php4.
                                                      +1
                                                      Посмотрел баги, о которых идет речь. Все относится к Windows-платформе. У большинства разработчиков php Windows вообще нет под рукой; поддержкой Windows-платформы занимается буквально пара человек — так что нет ничего удивительного. Правят баги по мере сил, как дойдут руки.

                                                      Так что, хотите помочь — присылайте патчи, попросите знакомого Windows/C-разработчика посмотреть, и так далее. Это не нежелание править баги, а простая проблема нехватки рук.
                                                        0
                                                        > По факту, я предпочту общение с людьми, которые помогают, а не просто требуют.

                                                        Чем кроме багрепорта может помочь человек не знающий C?

                                                        > Примерно это и делается, но постепенно. Сравните php 5.5 с php4.

                                                        До 5.3 никого развития по сути не было (5.0 => 5.2), а вот с него как раз началось бурное добавление новых фич. Да и переход с 4 на 5 выглядел очень логичным и радостным.

                                                        > Если же сложится ситуация, когда все только требуют

                                                        Тут как бы немного другая ситуация — они же сами решили стать мейтейнерами, а не просто слать патчи, а это, ИМХО, предполагает дополнительные обязанности.
                                                          0
                                                          Багрепорты, да, тут согласен. Но, впрочем, я знаю человека, который изучил C, исправляя баги в опенсорс-продукте. :)

                                                          5.0-5.2 действительно была некоторая стагнация. Люди со временем устают, теряют активный интерес, это, с сожалению, почти всегда происходит. Больше развития стало, когда пришли новые люди — не то, что они сами стали прямо вот все делать, скорее «растормошили» =)
                                                            +1
                                                            если вам так критично исправление этой проблемы, то что мешает вам нанять C-разработчика для того, чтобы он пофиксил этот баг? Вы ведь зарабатываете деньги при помощи php?
                                                              0
                                                              Конкретно эта проблема мешает переписыванию одной бесплатной утилиты для сборки аддонов к одному из форумов (работало оно через ant+php, сейчас же решил переписать на phing и вынести взаимодействие со сторонним кодом в другой процесс, но обломался :()
                                            0
                                            Спасибо за пост! Познавательно!

                                            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                            Самое читаемое