Массивы 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() здесь для каждого элемента. Мне пришлось бы немного изменить порядок и удалить всю конкатенацию, как сейчас. Есть ли другой простой способ сделать это, или я просто застрял с ним?
Ответы
Ответ 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);
}