Что PHP-замыкания возвращают в операторах IF? - PullRequest
8 голосов
/ 07 ноября 2011

Моя цель - поместить некоторую сложную логику в оператор 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».

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

Ответы [ 5 ]

6 голосов
/ 07 ноября 2011

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 и возвращает его возвращаемое значение.

3 голосов
/ 07 ноября 2011

Оба значения имеют значение true.

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

Попробуйте:

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

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

2 голосов
/ 07 ноября 2011

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

if (new Closure()) { ... }
1 голос
/ 07 ноября 2011

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

echo $q();
0 голосов
/ 07 ноября 2011

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

...