Подтвердить что ты не робот

Массивы PHP и решение для ошибок undefined index

Я работаю над некоторым кодом, сделанным предыдущим разработчиком. Я новичок в PHP, поэтому мне интересно, есть ли какой-либо известный шаблон или решение этой проблемы.

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

    /* snip */
"text" => $link . $top_pick_marker . $output['author'] . " " .  " " . 
                              $output['new_icon'] . $output['rec_labels'] . "   " 
                    . $output['admin_link']
                    . $output['alternate_title'] 
                    . $output['access_info'] 
                    . $output['description'] 
                    . $output['url']
                    . $output['subject_terms'] 
                    . $output['form_subdivisions'] 
                    . $output['dates_of_coverage']  
                    . $output['update_frequency']  
                    . $output['place_terms'],
    /* snip */

Итак, я знаю, что могу использовать isset() здесь для каждого элемента. Мне пришлось бы немного изменить порядок и удалить всю конкатенацию, как сейчас. Есть ли другой простой способ сделать это, или я просто застрял с ним?

4b9b3361

Ответ 1

Определите, какие ключи находятся в массиве $output, и заполните отсутствующие пустые строки.

$keys = array_keys($output);
$desired_keys = array('author', 'new_icon', 'admin_link', 'etc.');

foreach($desired_keys as $desired_key){
   if(in_array($desired_key, $keys)) continue;  // already set
   $output[$desired_key] = '';
}

Ответ 2

Вы можете использовать isset() без потери конкатенации:

//snip
$str = 'something'
 . ( isset($output['alternate_title']) ? $output['alternate_title'] : '' )
 . ( isset($output['access_info']) ? $output['access_info'] : '' )
 . //etc.

Вы также можете написать функцию, чтобы вернуть строку, если она установлена ​​- это, вероятно, не очень эффективно:

function getIfSet(& $var) {
    if (isset($var)) {
        return $var;
    }
    return null;
}

$str = getIfSet($output['alternate_title']) . getIfSet($output['access_info']) //etc

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

Ответ 3

Вариант ответа SquareRootOf2, но это должно быть помещено перед первым использованием переменной $output:

$keys = array('key1', 'key2', 'etc');
$output = array_fill_keys($keys, '');

Ответ 4

Если вы поддерживаете старый код, вы, вероятно, не можете стремиться к "наилучшему возможному коду когда-либо"... Этот случай, когда, на мой взгляд, вы можете снизить уровень error_reporting.

Этим "undefined index" должны быть только уведомления; поэтому вы можете установить уровень error_reporting для исключения уведомлений.

Одним из решений является функция error_reporting, например:

// Report all errors except E_NOTICE
error_reporting(E_ALL ^ E_NOTICE);

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

Другим решением было бы установить это в php.ini(может быть, не такая хорошая идея, если вы работаете над несколькими приложениями, тем не менее, поскольку это может маскировать полезные уведомления); см. error_reporting в php.ini.

Но я настаиваю: это приемлемо только потому, что вы поддерживаете старое приложение - вы не должны этого делать при разработке нового кода!

Ответ 5

Установить каждый индекс в массиве в начале (или до использования массива $output), вероятно, будет самым простым решением для вашего случая.

Пример

$output['admin_link'] = ""
$output['alternate_title'] = ""
$output['access_info'] = ""
$output['description'] = ""
$output['url'] = ""

Также не очень важно для вашего случая, но где вы сказали, что вы новичок в PHP, и это на самом деле не сразу очевидно. isset() может принимать несколько аргументов. Поэтому вместо этого:

if(isset($var1) && isset($var2) && isset($var3) ...){
    // all are set
}

Вы можете сделать:

if(isset($var1, $var2, $var3)){
   // all are set 
}

Ответ 6

Коротким решением является это (PHP 5.3 +):

$output['alternate_title'] = $output['alternate_title'] ?:'';

Вы получаете либо значение переменной, если оно не оценивается как false, либо ложное выражение. (Один после ":" )

Использование тернарного оператора без параметра "if true" вернет результат тестового выражения (первый). Поскольку undefined оценивается как false, возвращается ложное выражение.

В PHP 7 есть несколько более элегантный оператор Null-коалесценции:

$output['alternate_title'] = $output['alternate_title'] ?? '';

(Было бы хорошо с оператором присваивания по умолчанию, например '? =')

Ответ 7

Это самое быстрое решение, о котором я могу думать, но далеко не самое лучшее. Поэтому см. Это как "аварийное решение":

// ...
. @$output['admin_link']
. @$output['alternate_title'] 
. @$output['access_info'] 
// ... 

@ подавляет все предупреждения и ошибки PHP.

Ответ 8

Та же идея, что и Майкл Водопад

Из CodeIgniter

// Lets you determine whether an array index is set and whether it has a value.
// If the element is empty it returns FALSE (or whatever you specify as the default value.)
function element($item, $array, $default = FALSE)
{
    if ( ! isset($array[$item]) OR $array[$item] == "")
    {
        return $default;
    }

    return $array[$item];
}

Ответ 9

В моем случае я работаю, определив значение по умолчанию, если отправленные данные пусты. Вот что я наконец-то сделал (используя PHP7.3.5):

if(empty($_POST['auto'])){ $_POST['auto'] = ""; }

Ответ 10

Вы можете попробовать использовать небольшую функцию, которая вернет значение, если оно существует, или пустую строку, если нет. Это то, что я использую:

function arrayValueForKey($arrayName, $key) {
   if (isset($GLOBALS[$arrayName]) && isset($GLOBALS[$arrayName][$key])) {
      return $GLOBALS[$variable][$key];
   } else {
      return '';
   }
}

Затем вы можете использовать его следующим образом:

echo ' Values: ' . arrayValueForKey('output', 'admin_link') 
                 . arrayValueForKey('output', 'update_frequency');

И это не вызовет ошибок!

Надеюсь, это поможет!

Ответ 11

foreach($i=0; $i<10; $i++){
    $v = @(array)$v;   
    // this could help defining $v as an array. 
    //@ is to supress undefined variable $v

    array_push($v, $i);
}