Несколько возвращаемых значений для обозначения успеха / неудачи. - PullRequest
5 голосов
/ 16 сентября 2008

Мне интересно получить отзывы об этой технике, которую я откуда-то взял.

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

В основном, техника подразумевает возвращение true для успеха и что-то , которое приравнивает к false для неудачи. Вот пример, чтобы показать, что я имею в виду:

define ('DUPLICATE_USERNAME', false);
define ('DATABASE_ERROR', 0);
define ('INSUFFICIENT_DETAILS', 0.0);
define ('OK', true);

function createUser($username) {
    // create the user and return the appropriate constant from the above
}

Прелесть этого в том, что в вашем вызывающем коде, если вам все равно, ПОЧЕМУ создание пользователя не удалось, вы можете написать простой и читаемый код:

if (createUser('fred')) {
    // yay, it worked!
} else {
    // aww, it didn't work.
}

Если вы особенно хотите проверить, почему это не сработало (для регистрации, отображения пользователю или чего-либо еще), используйте сравнение идентификаторов с ===

$status = createUser('fred');
if ($status) {
    // yay, it worked!
} else if ($status === DUPLICATE_USERNAME) {
    // tell the user about it and get them to try again.
} else {
    // aww, it didn't work. log it and show a generic error message? whatever.
}

На мой взгляд, преимущества этого состоят в том, что это нормальное ожидание, что успешное выполнение подобной функции вернет true, а сбой вернет false.

Недостатком является то, что у вас может быть только 7 "error" return values: false, 0, 0.0, "0", null, "", and (object) null. Если вы забудете использовать проверку личности, вы можете получить неверный ход выполнения вашей программы. Кто-то еще сказал мне, что использование констант, таких как enum, где все они равны ложному, "ick".


Итак, чтобы сформулировать вопрос: насколько приемлема такая практика? Вы бы порекомендовали другой способ добиться того же?

Ответы [ 14 ]

0 голосов
/ 16 сентября 2008

Если вы действительно хотите делать такие вещи, у вас должны быть разные значения для каждой ошибки, и проверяйте на успешность. Что-то вроде

define ('OK', 0);
define ('DUPLICATE_USERNAME', 1);
define ('DATABASE_ERROR', 2);
define ('INSUFFICIENT_DETAILS', 3);

И проверьте:

if (createUser('fred') == OK) {
    //OK

}
else {
    //Fail
}
0 голосов
/ 16 сентября 2008

Посмотрите на COM HRESULT для правильного способа сделать это.

Но исключения, как правило, лучше.

Обновление: правильный путь: определите столько значений ошибок, сколько хотите, а не только «ложные». Используйте функцию successful (), чтобы проверить, успешно ли выполнена функция.

if (succeeded(result = MyFunction()))
  ...
else
  ...
0 голосов
/ 16 сентября 2008

Ик.

В предварительном исключении Unix это делается с помощью errno. Вы возвращаете 0 для успеха или -1 для ошибки, затем у вас есть значение, которое вы можете получить с целочисленным кодом ошибки, чтобы получить фактическую ошибку. Это работает во всех случаях, потому что у вас нет (реалистичного) ограничения на количество кодов ошибок. INT_MAX определенно больше 7, и вам не нужно беспокоиться о типе (errno).

Я голосую против решения, предложенного в вопросе.

0 голосов
/ 16 сентября 2008

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

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

class Result
{
    var $_result;
    var $_errormsg;

    function Result($res, $error)
    {
       $this->_result = $res;
       $ths->_errorMsg = $error
    }

    function getResult()
    {
       return $this->_result;
    }

    function isError()
    {
       return ! ((boolean) $this->_result);
    }

    function getErrorMessage()
    {
       return $this->_errorMsg;
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...