Заполнение массива PHP: сначала проверить индекс? - PullRequest
5 голосов
/ 04 октября 2008

Если я глубоко в гнезде петель, мне интересно, какой из них более эффективен:

if (!isset($array[$key])) $array[$key] = $val;

или

$array[$key] = $val;

Вторая форма намного более желательна для читаемого кода. На самом деле имена длиннее, а массив многомерен. Итак, первая форма в моей программе выглядит довольно мрачно.

Но мне интересно, может ли вторая форма быть медленнее. Поскольку код входит в число наиболее часто выполняемых функций в программе, я хотел бы использовать более быструю форму.

Вообще говоря, этот код будет выполняться много раз с одним и тем же значением $ key. Таким образом, в большинстве случаев $ array [$ key] уже будет установлен, а isset () вернет FALSE.

Чтобы пояснить тем, кто боится, что я отношусь к неидентичному коду, как будто он идентичен: для этой части программы $ val - это константа Это не известно до времени выполнения, но оно установлено ранее в программе и не изменяется здесь. Таким образом, обе формы дают одинаковый результат. И это самое удобное место, чтобы добраться до $ val.

Ответы [ 9 ]

10 голосов
/ 04 октября 2008

Для массива вы действительно хотите: array_key_exists($key, $array) вместо isset($array[$key]).

3 голосов
/ 04 октября 2008

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

Теперь первая форма может быть быстрее, если у вас есть больше установленных значений, чем тех, которые не установлены, просто потому, что она просто ищет хеш, не выбирая и не устанавливая значение. Таким образом, это может быть отличительной чертой: выберите первую форму, если у вас больше «хитов» по ​​заданным ключам, и выберите вторую, если у вас больше «промахов».

Обратите внимание, что эти два фрагмента кода не идентичны. Первая форма не будет устанавливать значение для некоторого ключа, когда он уже установлен - она ​​предотвращает «перезапись».

2 голосов
/ 04 октября 2008

Вы измерили, как часто вы сталкиваетесь с ситуацией, в которой устанавливается $array[$key], прежде чем пытаться ее установить? Я думаю, что нельзя дать общий совет по этому поводу, потому что если таких случаев действительно много, проверка isset может сэкономить некоторое время, избегая ненужных наборов в массиве. Однако, если это случается редко, накладные расходы могут замедлить вас ... Лучше всего сделать бенчмарк на вашем реальном коде.

Однако учтите, что оба кода могут привести к разным результатам ! Если $ val не всегда одинаков для комбинации $array[$key], первый код всегда будет устанавливать значение первого $val для этого $array[$key], где последний код всегда будет устанавливать его на последнее значение этой комбинации.

(Полагаю, вы знаете об этом, и $val всегда одинаков для $array[$key], но некоторые читатели могут остановиться.)

1 голос
/ 28 января 2009

Вы должны проверить массив до, но не включая уровень, который вы собираетесь установить.

Если вы собираетесь установить

$anArray[ 'level1' ][ 'level2' ][ 'level3' ] = ...

Вы должны убедиться, что путь до уровня 2 действительно существует до установки уровня 3.

$anArray[ 'level1' ][ 'level2' ]

Никакие щенки на самом деле не будут убиты, если вы этого не сделаете, но они могут быть раздражены в зависимости от вашей конкретной среды.

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

Существует простой способ сделать это:

<?php

function create_array_path( $path, & $inArray )
{
    if ( ! is_array( $inArray ) )
    {
        throw new Exception( 'The second argument is not an array!' );
    }
    $traversed = array();
    $current = &$inArray;

    foreach( $path as $subpath )
    {
        $traversed[] = $subpath;
        if ( ! is_array( $current ) )
        {
            $current = array();
        }
        if ( ! array_key_exists( $subpath, $current ) )
        {
            $current[ $subpath ] = '';
        }
        $current = &$current[ $subpath ];
    }
}


$myArray = array();

create_array_path( array( 'level1', 'level2', 'level3' ), $myArray );

print_r( $myArray );

?>

Будет выведено:

    Array
    (
        [level1] => Array
            (
                [level2] => Array
                    (
                        [level3] => 
                    )

            )

    )
1 голос
/ 04 октября 2008

Затраты на сравнение, которые могут или не могут быть правдой, кажутся такими, что это займет больше времени.

Что показывает выполнение сценария в обеих конфигурациях для увеличения производительности?

0 голосов
/ 06 октября 2008

Вы можете взглянуть на исходный код PHP, чтобы увидеть разницу. Не проверял, будет ли это отличаться в более поздних версиях PHP, но в PHP3 может показаться, что функциональность ассоциативного массива находится в php3 / php3_hash.c .

В функции _php3_hash_exists выполняются следующие действия:

  • ключ хэшируется
  • найдено правильное ведро
  • ковш шел, пока не найден правильный предмет или нет

Функция _php3_hash_add_or_update:

  • хэшируются
  • найдено ведро
  • прошел, существующий переопределен, если существует
    • если не существует, добавляется новый

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

0 голосов
/ 04 октября 2008

Я новичок в PHP, но комбинация обоих может быть с троичным оператором

$array[$key] = !isset($array[$key]) ? $val : $array[$key];

Это один из способов.

0 голосов
/ 04 октября 2008

Вам нужна фактическая проверка, чтобы увидеть, есть ли ключ? При присваивании пустому массиву isset() просто замедлит цикл. И если вы не сделаете второй проход с манипулированием данными, я настоятельно рекомендую не проверять isset. Это население, а не манипуляция.

0 голосов
/ 04 октября 2008

Дополнительный вызов функции isset () почти наверняка будет иметь больше служебных данных, чем любое назначение. Я был бы чрезвычайно удивлен, если вторая форма не быстрее.

...