Что возвращают замыкания PHP в операторах IF?

Моя цель — поместить сложную логику в оператор if(). Допустим, у меня есть массив значений, и я собираюсь выполнить часть кода, если все в моем массиве не равно нулю. Обычно я мог бы сказать $valid = true, foreach мой массив и установить $valid = false, когда будет найден ноль. Затем я запускал свой код if ($valid). В качестве альтернативы я мог бы поместить свой цикл в функцию и поместить функцию в свой if().

Но я ленивый, поэтому я не хочу возиться с кучей «валидных» флагов и не буду писать совершенно новую функцию, которая используется только в одном месте.

Итак, скажем, у меня есть это:

if ($q = function() { return 'foo'; }) {
  echo $q;
}
else {
  echo 'false';
}

Я ожидал, что if получит 'foo', что соответствует истине. Мое закрытие фиксируется на $q, и оператор выполняется. $q возвращает строку foo, и печатается 'foo'.

Вместо этого я получаю ошибку Object of class Closure could not be converted to string.

Итак, давайте попробуем это вместо этого:

if (function() { return false; }) {
  echo 'foo';
}
else {
  echo 'true';
}

Я ожидал, что моя функция вернет false и будет напечатано «true». Вместо этого печатается «foo».

Что не так в том, как я это делаю? Кажется, что он говорит: «Да, это точно функция!» вместо «Нет, потому что функция оценена как ложная». Есть ли способ сделать то, что я пытаюсь сделать?


person ajp5103    schedule 07.11.2011    source источник
comment
Кажется, вы путаете функции с их возвращаемыми значениями.   -  person    schedule 07.11.2011
comment
Я полагаю, что то, что я хотел, было ближе к if ( function() { return false; } () ) {, которое, по-видимому, допустимо в Javascript, но не в PHP.   -  person ajp5103    schedule 07.11.2011
comment
stackoverflow.com/questions/3568410/ call_user_func () это то, что я искал.   -  person ajp5103    schedule 14.11.2012


Ответы (5)


function() { return false; } создает объект типа Closure, аналогичный new с другими классами. типы, сравните следующий код:

$func = function() { return false; };

$func теперь является объектом. Каждый объект возвращает true в предложении if. Так

if ($func)
{
  # true
} else {
  # will never go here.
}

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

if ($func())
{
  # true
} else {
  # false
}

который вызовет объект Closure $func и даст ему возвращаемое значение.

person hakre    schedule 07.11.2011

Оба они оцениваются как истинные.

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

Попробуй это:

$q = function() { return false; };
if ($q()) { //should not go here.
  echo $q();
}
else {
  echo 'false';
}

Демонстрация: http://codepad.viper-7.com/Osym1s

person Naftali aka Neal    schedule 07.11.2011

Замыкания PHP реализованы как хак — объекты типа Closure. Ваш код фактически создает экземпляр объекта этого класса и присваивает его $q. В PHP результатом присваивания является присваиваемое значение, поэтому, по сути, ваш код сводится к

if (new Closure()) { ... }
person Marc B    schedule 07.11.2011

Вы не выполняете закрытие, когда вызываете echo, поэтому он пытается распечатать закрытие, а не результат закрытия:

echo $q();
person Andrew Marshall    schedule 07.11.2011

Вы создаете анонимную функцию, но никогда не выполняете ее. Когда вы тестируете $q = function() { return 'foo'; }, вы говорите: «Назначьте ссылку на эту анонимную функцию $q и пройдите этот тест, если $q не равен нулю» (разве PHP не забавен?)

Вам нужно вызвать замыкание и присвоить его результат $q перед тестированием и повторением $q.

person Chris Heald    schedule 07.11.2011