2012-05-27 2 views
10

Я пишу библиотеку PHP, и у меня есть проблема. У меня есть что-то похожее на следующее в моих интерфейсов:Как документировать @throws в документации на интерфейс

<?php 
/** 
* My interface 
* 
* ... 
*/ 
interface MyInterface 
{ 
    /** 
    * This method does foo. 
    * 
    * @throws \RuntimeException If foo can't be done. 
    */ 
    public function fooAndBar(); 
} 
?> 

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

Но другой разработчик может написать реализацию, которая не может потерпеть неудачу (поэтому она не может генерировать исключение), или он/она может захотеть использовать другой класс исключений.

В этой ситуации, как я должен документировать @throws в объявлениях интерфейса? Должен ли он быть документирован?

+0

Эта запись @throws предназначена только для целей документации (например, ApiGen), она не имеет ничего общего с фактическим кодом. В языке программирования Java есть ключевое слово 'throws', определяющее в интерфейсе, что какая-то функция бросает исключение и какое исключение он вызывает, в PHP нет, к сожалению. Если бы была такая функциональность, это заставило бы вас реализовать механизм catch catch в вашем коде, как вам нужно реализовать функции реализации. – sbrbot

+0

@sbrbot Хорошая документация по IDE + может быть частичной заменой для строгих языковых функций. – donquixote

+0

Ха, ха, этот комментарий почти 2 года (PHP4). Текущий PHP поддерживает исключения, такие как Java, и мой предыдущий комментарий больше недействителен. – sbrbot

ответ

5

Рассмотрим код, где вы потребляете интерфейс:

public function doSomething(MyInterface $my) { ... } 

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

Да, это должно быть документировано.

Даже если только одна реализация создает исключение, обработка исключений все еще должна быть на месте. Конечно, это не означает, что каждый метод должен иметь @throws. Он должен по-прежнему использоваться только там, где это необходимо (там, где вы ожидаете, что реализация законно должна вызвать исключение).

В более конкретном примере, рассмотрим следующее:

interface LogWriter 
{ 

    /** 
    * @throws LogWriterException 
    */ 
    public function write($entry); 

} 


class DbLogWriter 
{ 

    public function __construct(PDO $db) 
    { 
     //store $db somewhere 
    } 

    public function write($entry) 
    { 
     try { 
      //store $entry in the database 
     } catch (PDOException $e) { 
      throw new LogWriterException(...); 
     } 
    } 

} 

class NullLogWriter 
{ 
    public function write($entry) { } 
} 

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

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

И все же, если у вас есть $log и все, что вы знаете об этом, это реализация LogWriter. Вы предполагаете, что он не бросает исключений и потенциально случайно позволяет одному пузырю, или вы предполагаете, что он может выбросить ? Я остался бы в безопасности и предполагал, что это может вызвать исключение LogWriterException.

Если все, что пользователь знает, что $log является LogWriter, но только DbLogWriter документирован как бросать исключение, пользователь не может понять, что $log->write(...)может бросить исключение. Кроме того, когда позже будет создан FileLogWriter, это будет означать ожидания того, какие исключения, которые может быть реализована и, возможно, будет выбрано, будут уже установлены (никто не ожидал, что FileLogWriter будет выбросить RandomNewException).

8

Интерфейсы определяют контракты. Вне зависимости от того, реализует ли класс реализации исключение, это деталь реализации в PHP, потому что в сигнатуре метода нет (например, на Java) ключевого слова throws. Добавление аннотации @throws не может выполнить контракт технически, но может указывать соглашение (то же самое для возвращаемых значений btw).Достаточно ли этого достаточно, чтобы решить.

На стороне, если разработчик придумал реализацию, которая не бросает вас, у вас нет проблемы, потому что вам придется добавить блок try/catch в любом случае для тех реализаций, которые выполняют бросок (по соглашению). Было бы проблемой, если реализация начинает бросать другое исключение, чем указано в DocBlock, потому что тогда оно не будет выловлено.

Смежные вопросы