Условное присвоение значений PHP

Для очень распространенного случая присвоения значения переменной на основе результата выражения я поклонник тернарных операторов:

$foo = $bar ? $a : b;

Однако, если $bar — относительно дорогая операция, и я хочу присвоить результат $bar $foo, если результат правдив, это неэффективно:

$foo = SomeClass::bigQuery() ? SomeClass::bigQuery() : new EmptySet();

Один из вариантов:

$foo = ($result = SomeClass::bigQuery()) ? $result : new EmptySet();

Но я бы не хотел, чтобы лишнее $result сидело в памяти.

Лучший вариант, который у меня есть, это:

$foo = ($foo = SomeClass::bigQuery()) ? $foo : new EmptySet();

Или без тернарных операторов:

if(!$foo = SomeClass::bigQuery()) $foo = new EmptySet();

Или, если операторы потока программы не в вашем стиле:

($foo = SomeClass::bigQuery()) || ($foo = new EmptySet());

Так много вариантов, ни один из них не является действительно удовлетворительным. Что бы вы использовали, и я упустил что-то действительно очевидное здесь?


person Hamish    schedule 01.12.2010    source источник


Ответы (4)


PHP 5.3 представил новый синтаксис для решения именно этой проблемы:

$x = expensive() ?: $default;

См. документацию:

Начиная с PHP 5.3, можно опустить среднюю часть тернарного оператора.
Выражение expr1 ?: expr3 возвращает expr1, если expr1 оценивается как TRUE, и expr3 в противном случае.

person meagar    schedule 01.12.2010
comment
Лично я избегаю синтаксиса только для PHP 5.3 и предпочитаю $x = expensive(); if (!$x) $x = $default; - person meagar; 02.12.2010
comment
Вот это да; Я просто собирался прокомментировать, что PHP нуждается в расширении GNU для троичных - person Michael Mrozek; 02.12.2010
comment
ага - пропустил это в мануале. Я предполагаю, что это означает, что нет лучшего метода для 5.2.x (который я должен поддерживать в среднесрочной перспективе)? - person Hamish; 02.12.2010
comment
@Hamish: см. два других ответа;) . Но в любом случае отметьте это как ответ, потому что в вопросе не было указано, что меньше 5,3. - person Jonah; 02.12.2010
comment
Жаль, что PHP не пошел с решением Javascript/Actionscript: поскольку значение, обработанное в условном выражении, не приводится к логическому типу, если только оно не объединено с &&, вы можете сделать var x = expensive() || default; Это использует уже знакомый синтаксис и принесет пользу PHP не только один несколько эзотерический случай. - person Nicole; 02.12.2010
comment
@Renesis Я согласен - особенно с учетом того, что проверка «правдивости» PHP настолько свободна - это почти ошибка, когда логические операторы преобразуют объекты в логические! - person Hamish; 02.12.2010
comment
@DanyCaissy Я поздно понял, но, пожалуйста, не редактируйте справочную страницу на главной странице. Это не опечатка, узнайте, что такое справочные страницы. - person meagar; 21.12.2017
comment
@meagar Ха-ха, я думаю, вы имели в виду справочную страницу? Я не видел, чтобы его укорачивали таким образом в 2010 году ;) - person Dany Caissy; 22.12.2017

Можете ли вы обновить SomeClass:bigQuery(), чтобы он возвращал новый EmptySet() вместо false?

Тогда у вас просто есть

$foo = SomeClass::bigQuery();
person Jeff Davis    schedule 01.12.2010
comment
На самом деле это было бы моим предпочтением - к сожалению, я строю поверх библиотеки, которая допустила эту ошибку с нулевого дня, и теперь у них слишком много вещей, свисающих с API, чтобы исправить это:/ - person Hamish; 02.12.2010

Небольшое изменение вашего последнего варианта:

$foo = SomeClass::bigQuery() или new EmptySet(); на самом деле это не работает, спасибо, что заметили.

Часто используется в сочетании с кодом mySQL, но, кажется, всегда забывается в сопоставимых ситуациях:

$result = mysql_query($sql) or die(mysql_error());

Хотя лично я предпочитаю тот, который вы уже упомянули:

if(!$foo = SomeClass::bigQuery())
    $foo = new EmptySet();
person ontrack    schedule 01.12.2010
comment
На самом деле это нужно читать: $foo = SomeClass::bigQuery() or $foo = new EmptySet();, что эквивалентно 3-му варианту. - person Hamish; 02.12.2010

$foo = SomeClass::bigQuery();
if (!$foo) $foo = new EmptySet();

Вторая редакция, кредит @meagar

person Jonah    schedule 01.12.2010
comment
Это раздражающе многословно, я лично предпочитаю другие ответы. - person Core Xii; 02.12.2010
comment
Реализован способ уменьшить многословие. - person Jonah; 02.12.2010
comment
Почему не if (!$foo) $foo = new EmptySet();? Чуть меньше foo's. - person meagar; 02.12.2010
comment
Конечно, теперь это практически то же самое, что и ответ @ontrack. Тем не менее, я считаю, что задания никогда не должны быть в состоянии. - person Jonah; 02.12.2010