Почему появляются ошибки "undefined_index" и как их исправить?

23 июн. 2011 г., 13:14:20
Просмотры: 19.2K
Голосов: 4

Я буквально бьюсь головой об стену. Уверен, что это что-то очень простое, но я постоянно получаю ошибки undefined index для всех этих переменных.

function meta_genus_species() {
    global $post;

    if (isset($post)) {
        $custom = get_post_custom($post->ID);
    }

    if (isset($custom)) {
        $genus = $custom["genus"][0];    // Получаем значение рода
        $species = $custom["species"][0]; // Получаем значение вида
        $etymology = $custom["etymology"][0]; // Получаем этимологию
        $family = $custom["family"][0];  // Получаем семейство
        $common_names = $custom["common_names"][0]; // Получаем распространенные названия
    }

    ?>
<label>Род:</label>
<input name="genus" value="<?php if(isset($genus)) { echo $genus; } ?>" />
<label>Вид:</label>
<input name="species" value="<?php if(isset($species)) { echo $species; } ?>" />
<p><label>Этимология:</label><br />
<textarea cols="50" rows="5" name="etymology"><?php if(isset($etymology)) { echo $etymology; } ?></textarea></p>
<label>Семейство:</label>
<input name="family" value="<?php if(isset($family)) { echo $family; } ?>" />
<label>Распространенные названия:</label>
<input name="common_names" value="<?php if(isset($common_names)) { echo $common_names; } ?>" />
    <?php
}

Я получаю эту ошибку для каждой переменной:

Notice: Undefined index: genus в [...]sf-species-profiles.php на строке 207

Есть идеи?

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

какая строка кода является строкой 207?

Scott Scott
23 июн. 2011 г. 13:24:10

$genus = $custom["genus"][0];

turbonerd turbonerd
23 июн. 2011 г. 14:25:26
Все ответы на вопрос 3
2

Это распространённая ошибка в PHP, которая возникает при попытке обратиться к несуществующему ключу массива:

$array = array( 'hello' => 'world' );
echo $array['foobar']; // неопределённый индекс

Сначала следует проверить наличие ключа с помощью isset( $array['foobar'] );

ОБНОВЛЕНИЕ: В данном случае я бы использовал цикл, который автоматически устанавливает переменные, проверяя индексы в процессе:

foreach ( array( 'genus', 'species', 'etymology', 'family', 'common_names' ) as $var )
    $$var = isset( $custom[ $var ][0] ) ? $custom[ $var ][0] : '';

echo $genus; // выводит значение $custom['genus'][0], если оно существует, иначе пустую строку
23 июн. 2011 г. 13:23:26
Комментарии

Вы предлагаете использовать isset на каждой строке, например (псевдокод) isset($custom[genus]) > $genus=$custom[genus]? Неужели это чертовски долгий способ делать вещи? Я был под впечатлением (и это первый раз, когда я столкнулся с этой проблемой), что использование isset на $post, а затем и на $custom означало бы, что эти переменные не установлены/не существуют, если в $post нет данных?

turbonerd turbonerd
23 июн. 2011 г. 14:25:12

Вовсе нет - но в любом случае, вы никогда не должны предполагать, что X существует. Смотрите мой обновленный ответ :)

TheDeadMedic TheDeadMedic
23 июн. 2011 г. 14:52:54
5

Вы уже вызываете isset() каждый раз при выводе данных на экран.

Почему бы просто не пропустить эту часть:

if (isset($custom)) {
    $genus = $custom["genus"][0];
    $species = $custom["species"][0];
    $etymology = $custom["etymology"][0];
    $family = $custom["family"][0];
    $common_names = $custom["common_names"][0];
}

и делать так при выводе в поле ввода:

<label>Род:</label>
<input name="genus" value="<?php if( isset( $custom["genus"][0] ) ) { print $custom["genus"][0]; } ?>" />

Дополнительные присваивания переменных не нужны и вызывают появление уведомлений здесь.

Кстати...

Вам нужно экранировать вывод перед тем, как он будет отображен в форме:

<label>Род:</label>
<input name="genus" value="<?php if(isset($genus)) { echo esc_attr( $genus ); } ?>" />
<label>Вид:</label>
<input name="species" value="<?php if(isset($species)) { echo esc_attr( $species ); } ?>" />
<p><label>Этимология:</label><br />
<textarea cols="50" rows="5" name="etymology"><?php if(isset($etymology)) { echo esc_textarea( $etymology ); } ?></textarea></p>
<label>Семейство:</label>
<input name="family" value="<?php if(isset($family)) { echo esc_attr( $family ); } ?>" />
<label>Общие названия:</label>
<input name="common_names" value="<?php if(isset($common_names)) { echo esc_attr( $common_names ); } ?>" />
23 июн. 2011 г. 15:58:16
Комментарии

Да, я не заморачиваюсь с экранированием, пока код не заработает.. :) Я действительно думал сделать так, как вы предложили, но я немного фанатею за эстетику кода и, Боже мой, как же это ужасно выглядит! Спасибо.

turbonerd turbonerd
23 июн. 2011 г. 16:32:00

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

mfields mfields
23 июн. 2011 г. 16:39:22

ЛОЛ! По моему скромному мнению, взломанные сайты с фармацевтическими ссылками в футере выглядят куда ужаснее этого кода. ;)

John P Bloch John P Bloch
23 июн. 2011 г. 16:45:33

Не зацикливайтесь на том, что $custom["genus"][0] выглядит "менее красиво", чем $genus. Код @mfields в остальном абсолютно идентичен вашему, но при этом не вызовет ошибку. Пишите столько кода, сколько необходимо для решения задачи, не больше и не меньше.

EAMann EAMann
23 июн. 2011 г. 17:12:50

Хех, как верно заметил EAMann, проблема не в экранировании, которое кажется мне некрасивым — я имел в виду именно $custom["genus"][0] вместо $genus. Уж точно не предлагаю отказаться от экранирования данных из-за того, что это выглядит некрасиво.. :)

turbonerd turbonerd
23 июн. 2011 г. 17:41:38
1

Альтернативный вариант, который появился в обсуждении этого поста в Twitter, заключается в изменении способа получения данных. Функция get_post_custom() возвращает массив массивов, что и вызывает у вас сложности. Вместо неё я рекомендую использовать get_post_custom_values():

function meta_genus_species() {
    global $post;

    $genus = get_post_custom_values( 'genus', $post->ID );
    $species = get_post_custom_values( 'species', $post->ID );
    $etymology = get_post_custom_values( 'etymology', $post->ID );
    $family = get_post_custom_values( 'family', $post->ID );
    $common_names = get_post_custom_values( 'common_names', $post->ID );

    ?>
<label>Род:</label>
<input name="genus" value="<?php if(isset($genus[0])) { echo esc_attr( $genus[0] ); } ?>" />
<label>Вид:</label>
<input name="species" value="<?php if(isset($species[0])) { echo esc_attr( $species ); } ?>" />
<p><label>Этимология:</label><br />
<textarea cols="50" rows="5" name="etymology"><?php if(isset($etymology[0])) { echo esc_attr( $etymology ); } ?></textarea></p>
<label>Семейство:</label>
<input name="family" value="<?php if(isset($family[0])) { echo esc_attr( $family ); } ?>" />
<label>Обычные названия:</label>
<input name="common_names" value="<?php if(isset($common_names[0])) { echo esc_attr( $common_names ); } ?>" />
    <?php
}

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

23 июн. 2011 г. 17:10:00
Комментарии

Спасибо, EAMann. Я изучу пользовательские значения/метаданные, когда вернусь домой, а затем обдумаю этот подход.

turbonerd turbonerd
23 июн. 2011 г. 17:43:02