Какое более элегантное решение для этих вложенных операторов if/elseif?

Я создаю веб-сайт, который содержит пользователей с профилями пользователей. Многие поля в профиле являются необязательными.

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

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

  1. Если пользователь заполнил display_name, это будет отображаться.
  2. Если пользователь заполнил first_name и last_name, но не заполнил display_name, он отобразит оба имени.
  3. Если пользователь заполнил только first_name, он отобразит first_name.
  4. Если пользователь заполнил только last_name, он отобразит last_name.
  5. Если ничего не помогает, будет отображаться идентификатор пользователя, например user123.
  6. Если ни один из ключей массива не присутствует или параметр имеет значение NULL, имя будет отображаться как NULL

Метод работает отлично, но некрасиво. Должен быть способ украсить это альтернативой вложенным операторам if/else.

public function nameify($names = NULL) {
    $name = '';
    if (!empty($names)) {
        if (!empty($names['display_name'])) {
            $name = $names['display_name'];
        } elseif (!empty($names['first_name'])) {
            $name = $names['first_name'];
            if (!empty($names['last_name'])) {
                $name .= ' ' . $names['last_name'];
            }
        } elseif (!empty($names['last_name'])) {
            $name = $names['last_name'];
        }

        if (empty($name) && !empty($names['id'])) {
            $name = 'user' . $names['id'];
        } else {
            $name = 'NULL';
        }
    } else {
        $name = 'NULL';
    }
    return $name;
}

person Stephen    schedule 28.09.2010    source источник
comment
Вы просто неправильно используете оператор return. Его можно вызывать не только в конце функции, но и где угодно. И это прекратит дальнейшее выполнение. Как и goto. См. ответ x3ro для примера   -  person Your Common Sense    schedule 28.09.2010


Ответы (9)


public function nameify($names = NULL) {
    if ($names) {
        if (!empty($names['display_name'])) {
            return $names['display_name'];
        }
        if (!empty($names['first_name'])) {
            $name = $names['first_name'];
        } 
        if (!empty($names['last_name'])) {
            $name .= ' ' . $names['last_name'];
        }
        if (empty($name) && !empty($names['id'])) {
            $name = 'user' . $names['id'];
        }
    }
    return $name ? ltrim($name) : 'NULL';
}

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

РЕДАКТИРОВАТЬ: настроить, чтобы предотвратить возврат «NULL»

person Chuck Vose    schedule 28.09.2010
comment
Не проверяйте положительные результаты, а затем продолжайте внутри оператора if, а проверяйте на наличие ошибок и возвращайтесь, если они появляются. Таким образом вы уменьшите сложность и отступы. - person fresskoma; 28.09.2010
comment
@ x3ro в своем собственном ответе вы начали с того, что последовали своему совету, но второе условное выражение делает именно то, что вы говорите не делать. - person Stephen; 28.09.2010
comment
Возможно, я немного неточно выразился в своем комментарии, прошу прощения. Я не хотел сказать, что вы никогда не должны этого делать, но по возможности избегайте этого. В моем третьем выражении я сделал наоборот, потому что в противном случае мне понадобилось бы больше условий в выражении if. - person fresskoma; 28.09.2010
comment
С этим решением, хотя и очень читаемым, если пользователь вводит только фамилию, автор отображается как "NULL last_name" - person Stephen; 28.09.2010
comment
Вот почему null никогда не должен быть строкой ^^ - person fresskoma; 28.09.2010
comment
Спасибо, Стивен, ты прав. Я немного подправил, чтобы обойти это. - person Chuck Vose; 28.09.2010
comment
Большой! Я что-то делал с тройкой, смешанной с вашим решением, и это выглядело именно так. Спасибо! - person Stephen; 28.09.2010

Используя тернарные условия, мы можем сократить и украсить код:

public function nameify($names = NULL) {
    $name = 'NULL';

    if (!empty($names)) {

        $name = ($names['display_name']) ? $names['display_name'] : trim($names['first_name']." ".$names['last_name']);

        if(!$name) $name = ($names['id'] > 0) ? 'user'.$names['id'] : 'NULL';
    }

    return $name;
}
person Brendan Bullen    schedule 28.09.2010
comment
Я так не думаю. У меня включены предупреждения, и я ничего не получаю. Он просто увидит это как нулевое значение - person Brendan Bullen; 28.09.2010
comment
Упс. Я имел ввиду извещение. вот из документации php Attempting to access an array key which has not been defined is the same as accessing any other undefined variable: an E_NOTICE-level error message will be issued, and the result will be NULL. - person Stephen; 28.09.2010
comment
О да. У меня установлен уровень ошибки, чтобы игнорировать уведомления. Поскольку ожидаемый результат равен NULL, уведомление является просто информационным и не вызовет никаких проблем (если только у вас не включены уведомления, которые обычно не используются в производственной среде) - person Brendan Bullen; 28.09.2010

Я бы предложил это:

public function nameify($names = null) {
    if(empty($names))
        return null;

    if(!empty($names['display_name']))
        return $names['display_name'];

    if(!empty($names['first_name'])) {
        $name = $names['first_name'];
        if (!empty($names['last_name'])) {
            $name .= ' ' . $names['last_name'];
        }
        return $name;
    }

    if(!empty($names['id]))
        return 'user' . $names['id'];

    return null;
}
person fresskoma    schedule 28.09.2010

Это немного, но поскольку $name как минимум NULL:

public function nameify($names = NULL) {
    $name = 'NULL';
    if (!empty($names)) {
        if (!empty($names['display_name'])) {
            $name = $names['display_name'];
        } elseif (!empty($names['first_name'])) {
            $name = $names['first_name'];
            if (!empty($names['last_name'])) {
                $name .= ' ' . $names['last_name'];
            }
        } elseif (!empty($names['last_name'])) {
            $name = $names['last_name'];
        }

        if ($name=='NULL' && !empty($names['id'])) {
            $name = 'user' . $names['id'];
        } 
    } 
    return $name;
}
person CristiC    schedule 28.09.2010

Несколько менее читабельно, но эффективно):

list($idx,$name) = array_shift(array_filter(array(
    $names['display_name'],
    implode(' ',array_filter(array($names['first_name'],$names['last_name']))),
    'user'.$names['id'];
    )));
person Wrikken    schedule 28.09.2010
comment
-1 Несколько менее читабельно... Серьезно, кто будет что-то подобное отлаживать... Вот за это я ненавижу PHP... - person fresskoma; 28.09.2010
comment
Пожалуйста, не поймите неправильно мой комментарий, это отличная идея, просто никто никогда не должен использовать ее в производстве, если нет другого способа сделать это;) - person fresskoma; 28.09.2010
comment
Бах, мне нравится. Его можно было бы сделать более читаемым, но это прекрасный пример некоторых скрытых частей php. - person Chuck Vose; 28.09.2010
comment
@x3ro: Я согласен, что это то, что я бы никогда не использовал в производстве, просто мне пришлось выбросить решение без if после множества всех не-намного лучших ответов. Только в образовательных целях, и я бы не хотел, чтобы коллега пытался использовать подобные конструкции в производстве :) - person Wrikken; 28.09.2010

машина состояний очень хорошо работает для такой сложной логики. Его также очень просто реализовать (используя оператор switch).

person Jay    schedule 28.09.2010
comment
У вас есть пример того, как реализовать эту абстракцию для моей проблемы? Даже если это псевдокод, я бы хотел его увидеть. - person Stephen; 28.09.2010
comment
Хотя я принял ответ Чака Воса, я все еще заинтересован в этом. - person Stephen; 28.09.2010
comment
статическое перечисление { сон, работа, SurfStackOverflow, StareOutWindow, Game } состояние = сон; ClockChimeEvent () { переключатель (состояние) { case sleep: if ( час == 9 ) { состояние = SurfStackOverflow; } ломать; случай SurfStackOverflow: если (час == 10) { EatBreakfast(); состояние = работа; } ломать; пример: если ( час == 12 ) { EatLunch(); состояние = StareOutWindow ; } ломать; case StareOutWindow : if (hour == 17) { EatDinner(); состояние = игра; } ломать; case Game: если (час == 23) { EatSnack(); состояние = сон; } ломать; } } - person Jay; 29.09.2010

Не уверен, что мой вариант будет проще, но вот он:

public function nameify($names = null) {
    $result = array();

    if( !empty($names['display_name']) ) {
        array_push($result,$names['display_name']);
    } else {
        if( !empty($names['first_name']) ) {
            array_push($result, $names['first_name']);
        }
        if( !empty($names['last_name']) ) {
            array_push($result, $names['last_name']);
        }
    }

    if( empty($result) && !empty($names['id']) ) {
        array_push($result, 'user'.$names['id']);
    }

    return (empty($result) ? 'NULL' : implode(' ', $result));
}
person andreyv    schedule 28.09.2010

Я бы пошел с:

if( empty($names['display_name']) ) {
    $name = $names['first_name'] . ' ' $names['last_name'];
else
    $name = $names['display_name'];

$name = trim($name);
if( empty($name) ) 
    $name = 'user'.$names['id'];
if( empty($name) ) 
    $name = 'NULL';

Это будет «основная логика»… потребуются другие проверки, такие как $names != NULL или что-то в этом роде..

person jrharshath    schedule 28.09.2010
comment
Я думаю, вы имеете в виду empty, а не !empty в первой строке. - person Stephen; 28.09.2010
comment
@Стивен, ты прав. Будет редактировать. Пожалуйста, не стесняйтесь редактировать ответы других. - person jrharshath; 28.09.2010
comment
Если бы я мог. Для этого вам нужно 2000 повторений. - person Stephen; 28.09.2010

person    schedule
comment
@Stephen: это решение из мира Java) - person Stan Kurilin; 28.09.2010
comment
-1 Из-за двух вещей: максимальная сложность (== максимальное время отладки) и минимальная производительность (call_user_func чрезвычайно медленный в PHP) - person fresskoma; 28.09.2010
comment
@x3ro: минимальная производительность - да. сложность - нет. Гибкость - да! - person Stan Kurilin; 28.09.2010
comment
@Стас: Имхо, это намного сложнее, чем решение if/else. Все, о чем вам нужно подумать более 5 секунд, чтобы понять основную логику, сложно для такой задачи. Кроме того, автор не упомянул о каких-либо требованиях к гибкости. - person fresskoma; 28.09.2010
comment
@x3ro: Это только ваше ИМХО, так что .. Я думаю, что мы должны сначала думать о гибкости и читабельности, а не о производительности (в стандартных ситуациях) - person Stan Kurilin; 28.09.2010
comment
Я не согласен. Первое, о чем вы должны подумать при написании кода, — это удобство сопровождения и читабельность! Когда вы пишете гибкое решение, которое можете поддерживать только вы, это вообще никому не поможет. - person fresskoma; 28.09.2010
comment
@x3ro: Я думаю, это тема для холли вар) Мы работали с разными проектами, имеем разный опыт, читали разные книги и так далее, поэтому у нас разные ответы о приоритетах в программном обеспечении. - person Stan Kurilin; 28.09.2010
comment
@Stas: Да, но так почти с любой темой, связанной с программированием :D На самом деле, я не пытался никого обидеть... Я имею в виду, что никто не может быть объективным в таких вопросах, потому что мы все находимся под влиянием наш опыт :) - person fresskoma; 28.09.2010
comment
@x3ro: я думаю, что наши последние два сообщения будут счастливым завершением нашей дискуссии) - person Stan Kurilin; 28.09.2010