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

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

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

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

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

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

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

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


or return не работает, потому что return не считается «выражением» парсером языка – просто.

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

  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 токен T_LOGICAL_OR , за которым следует другое выражение.

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 в качестве кода состояния указывает на успех, поэтому вы, вероятно, захотите вернуть другое значение, чтобы указать, что вы не можете открыть файл.

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

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

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

это не ошибка

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

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

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

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

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

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

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

 connectMyDB() fallback return false; 

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

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