2008-10-03 2 views
5

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

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

или

$array[$key] = $val; 

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

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

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

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

ответ

1

Накладные расходы на сравнение, которое может быть или не быть правдой, похоже, должно занять больше времени.

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

0

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

+0

РНР руководство говорит, что «Исеть()» является «языковая конструкция», а не функция , Поэтому я ожидаю, что накладные расходы могут быть минимальными. Полагаю, мне нужно будет профилировать его и посмотреть. – 2008-10-03 20:27:37

3

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

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

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

+0

Две части кода фактически идентичны, если $ val является константой. Для моих целей это так. Отредактировал мой вопрос, чтобы прояснить это; Благодарю. – 2008-10-03 21:21:11

+0

Не уверен, что я понимаю ваш ответ: «выберите второй, если у вас больше« хитов »у уже установленного ключа». Вы говорите, что если $ array [$ key] уже будет установлен чаще, чем я, я должен * не * вызывать isset()? – 2008-10-03 21:24:29

2

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

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

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

0

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

10

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

0

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

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

, что один из способов, чтобы пойти с ним.

0

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

В функции _php3_hash_exists следующие вещи сделаны:

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

Функция _php3_hash_add_or_update :

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

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

1

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

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

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

Вы должны убедиться, что путь Шифрование до level2 на самом деле существует до установки LEVEL3.

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

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

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

<?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] => 
        ) 

      ) 

    ) 

 Смежные вопросы

  • Нет связанных вопросов^_^