Skip to content

Commit 06ef244

Browse files
authored
Add Throwable policy (#17)
* Add Throwable policy * Wording * Formatting * Expand on “May not just differ by message” * Phrasing * Expand on “Extension suffix” for additional exceptions * Allow throwing foreign exceptions for subclasses * Formatting
1 parent 823c8b8 commit 06ef244

File tree

1 file changed

+96
-0
lines changed

1 file changed

+96
-0
lines changed

coding-standards-and-naming.rst

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,102 @@ happen with the agreement of the parties involved). This document does not try
229229
to provide a hard guideline on what constitutes a sufficiently important
230230
library. The application of common sense is recommended.
231231

232+
Throwables
233+
==========
234+
235+
Newly introduced extensions MUST follow the following rules, existing extensions
236+
SHOULD follow the rules for newly introduced exceptions, but MAY diverge for
237+
consistency with existing symbols.
238+
239+
In the interest of readability the following text uses the word "exception" to
240+
refer to any kind of ``Throwable``. ``Exception`` in code blocks refers to the
241+
``\Exception`` class.
242+
243+
The class name of an exception MUST end in ``Exception`` (when extending from
244+
the ``Exception`` hierarchy) or ``Error`` (for the ``Error`` hierarchy).
245+
Exceptions MUST NOT be ``final``.
246+
247+
Extensions MUST have their own hierarchy of exceptions. At the lowest level of
248+
the hierarchy there MUST be a base ``Exception`` and base ``Error`` defined
249+
within the top-level of the extension's namespace. The unqualified class name of
250+
the base exceptions must be the name of the extension followed by ``Exception``
251+
or ``Error``. These base exceptions MUST directly extend from the global base
252+
``\Exception`` or ``\Error`` classes. The extension's base ``Error`` MAY be
253+
omitted if it is unused.
254+
255+
As an example, an extension called ``Example`` would define the following base
256+
exceptions:
257+
258+
.. code::
259+
260+
namespace Example;
261+
262+
class ExampleException extends \Exception { }
263+
class ExampleError extends \Error { }
264+
265+
An extension SHOULD define additional exceptions as appropriate to allow users
266+
to catch specific classes of exception for granular error handling. Any
267+
additional exception MUST either extend the extension's base exception or
268+
another exception defined by the extension. The unqualified class name of
269+
additional exceptions SHOULD be sufficiently specific to make collisions with
270+
the unqualified class name of other exceptions unlikely. The name of the
271+
extension SHOULD NOT be used within the unqualified class name of additional
272+
exceptions if the only purpose is to make the class name more unique.
273+
Specifically, the name of the extension SHOULD NOT be a simple prefix or suffix
274+
of the unqualified class name.
275+
276+
As an example, an additional exception for failing HTTP requests of the curl
277+
extension might be called ``Curl\FailedHttpRequestException``. This is
278+
sufficiently specific to avoid collisions, since using two different HTTP
279+
clients in a single source file is unlikely. It should not use
280+
``Curl\CurlFailedHttpRequestException``,
281+
``Curl\FailedCurlHttpRequestException``,
282+
``Curl\FailedHttpRequestCurlException``, or similar. A file extension however
283+
might want to define a ``File\FileNotFoundException`` and a
284+
``File\DirectoryNotFoundException``. In this case the name of the extension is a
285+
generic term and the ``File`` prefix in ``FileNotFoundException`` adds useful
286+
context to differentiate it from the ``DirectoryNotFoundException``.
287+
288+
An extension MUST NOT throw exceptions that it did not define itself, except for
289+
the global ``TypeError`` or ``ValueError`` exceptions thrown during parameter
290+
parsing and parameter validation, and (subclasses of) exceptions that are
291+
already defined to be thrown by a class that is subclassed itself. If an
292+
extension uses external functionality that may throw an exception it MUST wrap
293+
any exception thrown by that functionality into an appropriate exception of its
294+
own. It MUST set the ``$previous`` property to the original exception when doing
295+
so.
296+
297+
As an example, an extension that uses the CSPRNG must wrap the
298+
``Random\RandomException`` thrown on CSPRNG failure into an appropriate
299+
extension-specific exception.
300+
301+
The ``Error`` hierarchy MUST NOT be used for errors that are expected to be
302+
thrown (and caught) during normal operation of a PHP program.
303+
304+
As an example, a parsing function that is expected to be used with untrusted
305+
input must not throw an ``Error`` if the input is malformed. Similarly a
306+
function that interacts with the network must not throw an ``Error`` if the
307+
network operation fails. Any ``Error`` that is thrown should usually result in a
308+
reasonably obvious fix in the PHP program.
309+
310+
All exceptions MUST have a descriptive exception message intended for human
311+
consumption. Non-base exceptions MAY define additional properties to provide
312+
additional metadata about the nature of the error.
313+
314+
The exception message MUST NOT be the only means of distinguishing exception
315+
causes that the user might want to handle differently. Any two exceptions with
316+
different causes MUST be identifiable either by a unique exception class name, a
317+
stable ``$code``, or a class-specific additional property suitable for
318+
programmatic consumption (e.g. an enum).
319+
320+
As an example, in an HTTP client a connection failure due to a timeout is
321+
considered to be a different cause than a connection failure due to a
322+
non-existent hostname, as the user might want to schedule a retry when the
323+
connection times out, but not for unknown hostnames. If using the same
324+
``ConnectionFailureException`` class name for both errors, they must provide a
325+
property suitable for programmatic consumption and may not just differ in their
326+
exception message.
327+
232328
************************
233329
Implementation Details
234330
************************

0 commit comments

Comments
 (0)