В PHP, почему "или die()" работает, но "или возвращать" нет? - программирование
Подтвердить что ты не робот

В PHP, почему "или die()" работает, но "или возвращать" нет?

В PHP вы можете обрабатывать ошибки, вызывая or die для выхода, когда вы сталкиваетесь с определенными ошибками, например:

$handle = fopen($location, "r") or die("Couldn't get handle");

Использование die() - отличный способ обработки ошибок. Я предпочел бы вернуть код ошибки, чтобы родительская функция могла решить, что делать, а не просто заканчивать script безжалостно и отображать ошибку пользователю.

Однако PHP показывает ошибку, когда я пытаюсь заменить or die на or return, например:

$handle = fopen($location, "r") or return 0;

Почему работает or die(), но не or return 0?

4b9b3361

Ответ 1

Я хочу поблагодарить вас за задание этого вопроса, так как я понятия не имел, что вы не можете выполнить or return в PHP. Я был так же удивлен, как и ты, когда я его протестировал. Этот вопрос дал мне хороший повод провести какое-то исследование и поиграть в PHP, что было довольно забавно. Тем не менее, я не специалист по внутренним функциям PHP, поэтому следующее представление непрофессионала внутри PHP, хотя я считаю это довольно точным.


or return не работает, потому что return не рассматривается как выражение для парсера языка - просто.

Ключевое слово or определено на языке PHP как токен под названием T_LOGICAL_OR, и единственное выражение, в котором оно определено, выглядит как this:

 expr T_LOGICAL_OR { zend_do_boolean_or_begin(&$1, &$2 TSRMLS_CC); } expr { zend_do_boolean_or_end(&$$, &$1, &$4, &$2 TSRMLS_CC); }

Не беспокойтесь о битах в фигурных скобках - это просто определяет, как обрабатывается фактическая "или" логика. То, что у вас осталось, - это expr T_LOGICAL_OR expr, который просто говорит, что это допустимое выражение для выражения, за которым следует токен T_LOGICAL_OR, за которым следует другое выражение.

An expr также определяется парсером, как и следовало ожидать. Это может быть либо r_variable, что означает, что это переменная, которую вы разрешили читать, или expr_without_variable, что является причудливым способом сказать, что выражение может быть сделано из других выражений.

Вы можете сделать or die(), потому что языковая конструкция die (а не функция!) и ее псевдоним exit оба представлены токеном T_EXIT, а T_EXIT считается действительным expr_without_variable, тогда как оператор return - токен T_RETURN - не является.

Теперь, почему T_EXIT считается выражением, но T_RETURN не является? Честно говоря, я понятия не имею. Возможно, это был просто дизайн, сделанный только для того, чтобы разрешить конструкцию or die(), о которой вы спрашиваете. Тот факт, что он был настолько широко использован - по крайней мере, в таких вещах, как учебники, поскольку я не могу говорить с большим объемом производственного кода, похоже, подразумевает, что это может быть преднамеренным выбором. Вы должны были бы попросить разработчиков языка знать наверняка.


Со всем сказанным это не имеет значения. Хотя конструкция or die() казалась вездесущей в учебниках (см. Выше) несколько лет назад, это не рекомендуется, так как это пример "умного кода". or die() не является собственной конструкцией, а скорее трюком, который использует - некоторые могут сказать, злоупотребления - два побочных эффекта оператора or:

  • он очень мал в списке приоритетов операторов, что означает, что практически каждое другое выражение будет оцениваться до того, как оно будет
  • это оператор короткого замыкания, что означает, что второй операнд (бит после or) не выполняется, если первый операнд возвращает TRUE, так как если один операнд TRUE в or, то оба они.

Некоторые считают, что этот тип обмана является неблагоприятным, поскольку программисту еще труднее читать, но только сохраняет несколько символов пространства в исходном коде. Поскольку время программиста дорого, а дисковое пространство дешево, вы можете понять, почему людям это не нравится.

Вместо этого вы должны четко указать свое намерение, расширив свой код до полноценного оператора if:

$handle = fopen($location, "r");
if ($handle) {
  // process the file
} else {
  return 0;
}

Вы даже можете выполнить присвоение переменной в инструкции if. Некоторые люди все еще считают это нечитаемым, но большинство людей (включая меня) не согласны:

if ($handle = fopen($location, "r")) {
  // process the file
} else {
  return 0;
}

Последнее: соглашение о возврате 0 в качестве кода состояния указывает на успех, поэтому вы, вероятно, захотите вернуть другое значение, чтобы указать, что вы не можете открыть файл.

Ответ 2

Я тоже наткнулся на это. Все, что я мог найти, это:

https://bugs.php.net/bug.php?id=40712

Посмотрите на комментарий ниже:

это не ошибка

Я искал в документации, и я думаю, это связано с тем, что return 0 является выражением, тогда как die() по существу является выражением. Вы не можете запустить $handle = return 0;, но $handle = fun(); - действительный код.

Что касается обработки ошибок, я бы рекомендовал настраиваемые коды или использовать пользовательские обработчики и триггеры. Последние описаны здесь.

Ответ 3

Возврат довольно особенный - он не может быть чем-то вроде функции, поскольку это инструмент для выхода из функций. Представьте себе следующее:

if(1==1) return();  // say what??

Если бы это было так, возвращение должно было бы быть функцией, которая выполняет "двойной выход", оставляя не только свою собственную область видимости, но и вызывающую. Следовательно, возврат не похож на выражение, он просто не может работать таким образом.

Теперь теоретически возвращение может быть выражением, которое оценивает (скажем) false и затем завершает работу; возможно, более поздняя версия PHP выполнит это.

То же самое относится к goto, что было бы прелестью работать как резерв; и да, резервные копии необходимы и часто делают код читаемым, поэтому, если кто-то жалуется на "умный код" (что, безусловно, является хорошим моментом), возможно, php должен иметь некоторый "официальный" способ сделать такую ​​вещь:

connectMyDB() fallback return false;

Что-то вроде try... catch, только больше. И лично, я был бы намного счастливее с "или" выполняя эту работу, так как она хорошо работает с английской грамматикой: "соедините или сообщите о неудаче".

TL;DR: вы абсолютно правы: return, goto, break - никто из них не работает. Легко понять, почему, но все еще раздражает.