Подтвердить что ты не робот

Почему и как вы используете Исключения в этом примере кода PHP?

Мне было интересно, зачем использовать Исключения в моем PHP. Давайте рассмотрим простой пример:

class Worker
{
 public function goToWork()
 {
  return $isInThatMood ?
  // Okay, I'll do it.
  true : 
  // In your dreams...
  false;
 }
}

$worker = new Worker;
if (!$worker->goToWork())
{
 if (date('l',time()) == 'Sunday')
  echo "Fine, you don't have to work on Sundays...";
 else
  echo "Get your a** back to work!";
}
else
 echo "Good.";

Есть ли причина для использования Исключения для такого кода? Зачем? Как будет построен код?

А как насчет кода, который может вызвать ошибки:

class FileOutputter
{
 public function outputFile($file)
 {
  if (!file_exists($file))
   return false;
  return file_get_contents($file);
 }
}

Почему я должен использовать Исключения в приведенном выше случае? У меня такое чувство, что Исключения помогают вам распознать тип проблемы, которая произошла, правда?

Итак, я правильно использую Исключения в этом коде:

class FileOutputter
{
 public function outputFile($file)
 {
  if (!file_exists($file))
   return throw new Exception("File not found.",123);
  try
  {
   $contents = file_get_contents($file);
  }
  catch (Exception $e)
  {
   return $e;
  }
  return $contents;
 }
}

Или это бедно? Теперь базовый код может сделать это:

$fo = new FileOutputter;
try
{
 $fo->outputFile("File.extension");
}
catch (Exception $e)
{
 // Something happened, we could either display the error/problem directly
 echo $e->getMessage();
 // Or use the info to make alternative execution flows
 if ($e->getCode() == 123) // The one we specified earlier
  // Do something else now, create "an exception"
}

Или я полностью потерялся здесь?

4b9b3361

Ответ 1

Когда следует использовать исключение?

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

Например, у вас может быть метод Record::save(), который сохраняет изменения в записи в базу данных. Если по какой-либо причине это невозможно сделать (например, произошла ошибка базы данных или нарушение данных), вы можете указать исключение для указания отказа.

Как создать пользовательские исключения?

Исключения обычно называются такими, что они указывают характер ошибки, например DatabaseException. Вы можете подклассифицировать Exception, чтобы создавать измененные имена с таким именем, например.

class DatabaseException extends Exception {}

(Конечно, вы можете воспользоваться наследованием, чтобы, например, предоставить этому исключению дополнительную диагностическую информацию, такую ​​как сведения о соединении или код ошибки базы данных.)

Когда не следует использовать исключение?

Рассмотрим еще один пример; метод, который проверяет существование файла. Вероятно, это не должно вызывать исключения, если файл не существует, поскольку цель метода заключалась в выполнении указанной проверки. Однако метод, который открывает файл и выполняет некоторую обработку, может генерировать исключение, поскольку файл должен существовать и т.д.

Изначально это не всегда ясно, когда что-то есть и не является исключительным. Как и большинство вещей, опыт научит вас со временем, когда вы должны и не должны бросать исключение.

Зачем использовать исключения вместо возврата специальных кодов ошибок и т.д.?

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

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

Ответ 2

Я не программист на PHP, но это похоже на С#.

Обычно вы хотите выбросить ошибки, если это точка возврата. Тогда вы сможете зарегистрировать что-то, чтобы показать, что произошло невозможное.

Если вы можете сказать, что файл не существует, вы можете просто сказать это. Никакой реальной потребности в моем уме, чтобы также исключить.

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

Я бы сказал, что это хорошая практика проектирования, чтобы избежать уловов всех исключений "catch (Exception $e)" и дизайна по контракту вместо этого, как вы, кажется, делаете в предыдущем примере. Сначала я был бы более конкретным с типом исключения, который был бы выброшен, а затем работал оттуда, если это необходимо. В противном случае держитесь подальше от try- > catch и исключений.

Ответ 3

Ни в коем случае нельзя предположить, что файл существует только потому, что вы вызвали file_exists()! Функция file_exists не открывает файл, поэтому файл может быть удален или переименован или перемещен в любое время!

class FileOutputter
{
    public function outputFile($file)
    {
        if (!file_exists($file))
            return false;
        ///<--- file may be deleted right here without you knowing it
        return file_get_contents($file);//<-- then this will throw an error
            //if you don't catch it, you're program may halt.
    }
}

Я считаю, что это лучше:

class FileOutputter
{
    public function outputFile($file)
    {
        try{
            if (!file_exists($file))
                return false;
            return file_get_contents($file);
        }catch(Exception e){
            check_what_went_wrong_and_go_to_plan_B();
        }
    }
}

(Edit: И, вероятно, даже лучше попытаться открыть файл с самого начала. Если вам это удастся, тогда у вас есть "блокировка" в файле, и он не просто исчезнет. Если нет, то поймайте исключение и посмотрите, что пошло не так.

И снова вы можете почувствовать, что этот уровень перераспределения просто глупо. В этом случае я не думаю, что вам нужно беспокоиться о try/catch вообще:)

Ответ 4

Просто заметьте, что ваш код для выходного файла недействителен, так как file_get_contents ($ file) не генерирует исключение. Однако он будет вызывать предупреждение, если файл не существует или недоступен по какой-либо причине. Кроме того, вы возвращаете исключение из outputFile, когда вы, вероятно, должны просто позволить распространению ошибки в стеке вызовов.

Однако вы можете зарегистрировать обработчик ошибок в php для исключения исключений при возникновении ошибки:

function exception_error_handler($errno, $errstr, $errfile, $errline ) {
    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
set_error_handler("exception_error_handler");

Таким образом, любые вызовы стандартных функций, вызывающие ошибку, генерируют исключение.

Итак, я бы изменил FileOutputter на это (с добавлением этого фрагмента выше):

class FileOutputter
{
 public function outputFile($file)
 {
  if (!file_exists($file))
   throw new Exception("File not found.",123);

   return file_get_contents($file);  
 }
}

Вызывающий код тогда в основном тот же.

В основном правило - не возвращать исключение при возникновении ошибки - вы можете поймать его, если хотите, и выбросить настраиваемое исключение, но пусть исключение перейдет в стек вызовов, пока вы не захотите его использовать.