[prev in list] [next in list] [prev in thread] [next in thread]
List: pear-doc
Subject: [PEAR-DOC] cvs: peardoc /fr/chapters standards.xml
From: "Christophe Gesché" <moosh () php ! net>
Date: 2006-12-30 17:54:48
Message-ID: cvsmoosh1167501288 () cvsserver
[Download RAW message or body]
moosh Sat Dec 30 17:54:48 2006 UTC
Modified files:
/peardoc/fr/chapters standards.xml
Log:
- sync to en-1.50
* Added section for the new rule that code must be E_STRICT compatible.
* Added exception handling guidelines for PHP 5 code.
["moosh-20061230175448.txt" (text/plain)]
http://cvs.php.net/viewvc.cgi/peardoc/fr/chapters/standards.xml?r1=1.37&r2=1.38&diff_format=u
Index: peardoc/fr/chapters/standards.xml
diff -u peardoc/fr/chapters/standards.xml:1.37 peardoc/fr/chapters/standards.xml:1.38
--- peardoc/fr/chapters/standards.xml:1.37 Sat Dec 30 17:48:10 2006
+++ peardoc/fr/chapters/standards.xml Sat Dec 30 17:54:48 2006
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="iso-8859-1" ?>
-<!-- $Revision: 1.37 $ -->
-<!-- EN-Revision: 1.45 Maintainer: moosh Status: ready -->
+<!-- $Revision: 1.38 $ -->
+<!-- EN-Revision: 1.50 Maintainer: moosh Status: not full ready -->
<chapter id="standards">
<title>Convention de codage</title>
@@ -868,6 +868,528 @@
</para>
</sect1>
+
+ <sect1 id="standards.e_strict">
+ <title><literal>E_STRICT</literal>-compatible code</title>
+ <para>
+ Starting on 01 January 2007, all new code that is suggested for
+ inclusion into PEAR must be
+ <literal>E_STRICT</literal>-compatible. This means that it must
+ not produce any warnings or errors when PHP's error reporting level
+ is set to <literal>E_STRICT</literal>.
+ </para>
+ <para>
+ The development of existing packages that are not
+ <literal>E_STRICT</literal>-compatible can continue as usual. If
+ however a new <emphasis>major</emphasis> version of the package is
+ released, this major version must then be
+ <literal>E_STRICT</literal>-compatible.
+ </para>
+ <para>
+ More details on this part of the Coding Standards can be found in
+ the corresponding <ulink url="&url.pear.pepr.proposal;419">PEPr
+ proposal</ulink>.
+ </para>
+ </sect1>
+
+ <sect1 id="standars.errors">
+ <title>Error Handling Guidelines</title>
+
+ <abstract>
+ <para>
+ This part of the Coding Standards describes how errors are
+ handled in PEAR packages that are developed for PHP 5 and 6. It
+ uses Exceptions, introduced in PHP 5.0 with Zend Engine 2, as
+ the error handling mechanism.
+ </para>
+ </abstract>
+
+ <sect2>
+ <title>Definition of an error</title>
+
+ <para>
+ An error is defined as an unexpected, invalid program state from
+ which it is impossible to recover. For the sake of definition,
+ recovery scope is defined as the method scope. Incomplete
+ recovery is considered a recovery.
+ </para>
+
+ <example>
+ <title>One pretty straightforward example for an error</title>
+ <programlisting role="php">
+ <![CDATA[
+/*
+ * Connect to Specified Database
+ *
+ * @throws Example_Datasource_Exception when it can't connect
+ * to specified DSN.
+ */
+function connectDB($dsn) {
+ $this->db =& DB::connect($dsn);
+ if (DB::isError($this->db)) {
+ throw new Example_Datasource_Exception(
+ "Unable to connect to $dsn:" . $this->db->getMessage()
+ );
+ }
+}
+ ]]>
+ </programlisting>
+ </example>
+
+ <para>
+ In this example the objective of the method is to connect to the
+ given DSN. Since it can't do anything but ask PEAR DB to do it,
+ whenever DB returns an error, the only option is to bail out and
+ launch the exception.
+ </para>
+
+ <example>
+ <title>Error handling with recovery</title>
+
+ <programlisting role="php">
+ <![CDATA[
+/*
+ * Connect to one of the possible databases
+ *
+ * @throws Example_Datasource_Exception when it can't connect to
+ * any of the configured databases.
+ *
+ * @throws Example_Config_Exception when it can't find databases
+ * in the configuration.
+ */
+
+function connect(Config $conf) {
+ $dsns =& $conf->searchPath(array('config', 'db'));
+ if ($dsns === FALSE) throw new Example_Config_Exception(
+ 'Unable to find config/db section in configuration.'
+ );
+
+ $dsns =& $dsns->toArray();
+
+ foreach($dsns as $dsn) {
+ try {
+ $this->connectDB($dsn);
+ return;
+ } catch (Example_Datasource_Exception e) {
+ // Some warning/logging code recording the failure
+ // to connect to one of the databases
+ }
+ }
+ throw new Example_Datasource_Exception(
+ 'Unable to connect to any of the configured databases'
+ );
+}
+ ]]>
+ </programlisting>
+ </example>
+
+ <para>
+ This second example shows an exception being caught and
+ recovered from. Although the lower level
+ <function>connectDB</function> method is unable to do anything
+ but throw an error when one database connection fails, the upper
+ level <function>connect</function> method knows the object can
+ go by with any one of the configured databases. Since the error
+ was recovered from, the exception is silenced at this level and
+ not rethrown.
+ </para>
+
+ <example>
+ <title>Incomplete recovery</title>
+
+ <programlisting role="php">
+ <![CDATA[
+/*
+ * loadConfig parses the provided configuration. If the configuration
+ * is invalid, it will set the configuration to the default config.
+ *
+ */
+function loadConfig(Config $conf) {
+ try {
+ $this->config = $conf->parse();
+ } catch (Config_Parse_Exception e) {
+ // Warn/Log code goes here
+ // Perform incomplete recovery
+ $this->config = $this->defaultConfig;
+ }
+}
+ ]]>
+ </programlisting>
+ </example>
+
+ <para>
+ The recovery produces side effects, so it is considered
+ incomplete. However, the program may proceed, so the exception
+ is considered handled, and must not be rethrown. As in the
+ previous example, when silencing the exception, logging or
+ warning should occur.
+ </para>
+ </sect2>
+
+ <sect2>
+ <title>Error Signaling in PHP 5 PEAR packages</title>
+
+ <para>
+ Error conditions in PEAR packages written for PHP 5 must be
+ signaled using exceptions. Usage of return codes or return
+ <classname>PEAR_Error</classname> objects is deprecated in favor
+ of exceptions. Naturally, packages providing compatibility with
+ PHP 4 do not fall under these coding guidelines, and may thus
+ use the error handling mechanisms defined in the PHP 4 PEAR
+ coding guidelines.
+ </para>
+ <para>
+ An exception should be thrown whenever an error condition is
+ met, according to the definition provided in the previous
+ section. The thrown exception should contain enough information
+ to debug the error and quickly identify the error cause. Note
+ that, during production runs, no exception should reach the
+ end-user, so there is no need for concern about technical
+ complexity in the exception error messages.
+ </para>
+ <para>
+ The basic <classname>PEAR_Exception</classname> contains a
+ textual error, describing the program state that led to the
+ throw and, optionally, a wrapped lower level exception,
+ containing more info on the lower level causes of the error.
+ </para>
+ <para>
+ The kind of information to be included in the exception is
+ dependent on the error condition. From the point of view of
+ exception throwing, there are three classes of error conditions:
+ </para>
+
+ <orderedlist>
+ <listitem>
+ <simpara>
+ Errors detected during precondition checks
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ Lower level library errors signaled via error return codes
+ or error return objects
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ Uncorrectable lower library exceptions
+ </simpara>
+ </listitem>
+ </orderedlist>
+
+ <para>
+ Errors detected during precondition checks should contain a
+ description of the failed check. If possible, the description
+ should contain the violating value. Naturally, no wrapped
+ exception can be included, as there isn't a lower level cause of
+ the error. Example:
+ </para>
+
+ <example>
+ <title />
+ <programlisting role="php">
+ <![CDATA[
+function divide($x, $y) {
+ if ($y == 0) {
+ throw new Example_Aritmetic_Exception('Division by zero');
+ }
+}
+ ]]>
+ </programlisting>
+ </example>
+
+ <para>
+ Errors signaled via return codes by lower level libraries, if
+ unrecoverable, should be turned into exceptions. The error
+ description should try to convey all information contained in
+ the original error. One example, is the connect method
+ previously presented:
+ </para>
+
+ <example>
+ <title />
+ <programlisting role="php">
+ <![CDATA[
+/*
+ * Connect to Specified Database
+ *
+ * @throws Example_Datasource_Exception when it can't connect to specified DSN.
+ */
+function connectDB($dsn) {
+ $this->db =& DB::connect($dsn);
+ if (DB::isError($this->db)) {
+ throw new Example_Datasource_Exception(
+ "Unable to connect to $dsn:" . $this->db->getMessage()
+ );
+ }
+}
+ ]]>
+ </programlisting>
+ </example>
+
+ <para>
+ Lower library exceptions, if they can't be corrected, should
+ either be rethrown or bubbled up. When rethrowing, the original
+ exception must be wrapped inside the one being thrown. When
+ letting the exception bubble up, the exception just isn't
+ handled and will continue up the call stack in search of a
+ handler.
+ </para>
+
+ <example>
+ <title>Rethrowing an exception</title>
+
+ <programlisting role="php">
+ <![CDATA[
+function preTaxPrice($retailPrice, $taxRate) {
+ try {
+ return $this->divide($retailPrice, 1 + $taxRate);
+ } catch (Example_Aritmetic_Exception e) {
+ throw new Example_Tax_Exception('Invalid tax rate.', e);
+ }
+}
+ ]]>
+ </programlisting>
+ </example>
+
+ <example>
+ <title>Letting exceptions bubble up</title>
+
+ <programlisting role="php">
+ <![CDATA[
+function preTaxPrice($retailPrice, $taxRate) {
+ return $this->divide($retailPrice, 1 + $taxRate);
+}
+ ]]>
+ </programlisting>
+ </example>
+
+ <para>
+ The case between rethrowing or bubbling up is one of software
+ architecture: Exceptions should be bubbled up, except in these
+ two cases:
+ </para>
+
+ <orderedlist>
+ <listitem>
+ <simpara>
+ The original exception is from another package. Letting it
+ bubble up would cause implementation details to be exposed,
+ violating layer abstraction, conducing to poor design.
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ The current method can add useful debugging information to
+ the received error before rethrowing.
+ </simpara>
+ </listitem>
+ </orderedlist>
+ </sect2>
+
+ <sect2>
+ <title>Exceptions and normal program flow</title>
+
+ <para>
+ Exceptions should never be used as normal program flow. If
+ removing all exception handling logic (try-catch statements)
+ from the program, the remaining code should represent the
+ "One True Path" -- the flow that would be executed in
+ the absence of errors.
+ </para>
+ <para>
+ This requirement is equivalent to requiring that exceptions be
+ thrown only on error conditions, and never in normal program
+ states.
+ </para>
+ <para>
+ One example of a method that wrongly uses the bubble up
+ capability of exceptions to return a result from a deep
+ recursion:
+ </para>
+
+ <example>
+ <title />
+ <programlisting role="php">
+ <![CDATA[
+/**
+ * Recursively search a tree for string.
+ * @throws ResultException
+ */
+public function search(TreeNode $node, $data) {
+ if ($node->data === $data) {
+ throw new ResultException( $node );
+ } else {
+ search( $node->leftChild, $data );
+ search( $node->rightChild, $data );
+ }
+}
+ ]]>
+ </programlisting>
+ </example>
+
+ <para>
+ In the example the ResultException is simply using the
+ "eject!" qualities of exception handling to jump out
+ of deeply nested recursion. When actually used to signify an
+ error this is a very powerful feature, but in the example above
+ this is simply lazy development.
+ </para>
+ </sect2>
+
+ <sect2>
+ <title>Exception class hierarchies</title>
+
+ <para>
+ All of PEAR packages exceptions must be descendant from
+ <classname>PEAR_Exception</classname>. <classname>PEAR_Exception</classname>
+ provides exception wrapping abilities, absent from the top level
+ PHP Exception class, and needed to comply with the previous
+ section requirements.
+ </para>
+ <para>
+ Aditionally, each PEAR package must provide a top level
+ exception, named <Package_Name>_Exception. It is
+ considered best practice that the package never throws
+ exceptions that aren't descendant from its top level exception.
+ </para>
+ </sect2>
+
+ <sect2>
+ <title>Documenting Exceptions</title>
+
+ <para>
+ Because PHP, unlike Java, does not require you to explicitly
+ state which exceptions a method throws in the method signature,
+ it is critical that exceptions be thoroughly documented in your
+ method headers.
+ </para>
+
+ <example>
+ <title>
+ Exceptions should be documented using the
+ <literal>@throws</literal> phpdoc keyword
+ </title>
+
+ <programlisting role="php">
+ <![CDATA[
+/**
+ * This method searches for aliens.
+ *
+ * @return array Array of Aliens objects.
+ * @throws AntennaBrokenException If the impedence readings indicate
+ * that the antenna is broken.
+ *
+ * @throws AntennaInUseException If another process is using the
+ * antenna already.
+ */
+public function findAliens($color = 'green');
+ ]]>
+ </programlisting>
+ </example>
+
+ <para>
+ In many cases middle layers of an application will rewrap any
+ lower-level exceptions into more meaningful application
+ exceptions. This also needs to be made clear:
+ </para>
+
+ <example>
+ <title />
+ <programlisting role="php">
+ <![CDATA[
+/**
+ * Load session objects into shared memory.
+ *
+ * @throws LoadingException Any lower-level IOException will be wrapped
+ * and re-thrown as a LoadingException.
+ */
+public function loadSessionObjects();
+ ]]>
+ </programlisting>
+ </example>
+
+ <para>
+ In other cases your method may simply be a conduit through which
+ lower level exceptions can pass freely. As challenging as it may
+ be, your method should also document which exceptions it is
+ <emphasis>not</emphasis> catching.
+ </para>
+
+ <example>
+ <title />
+ <programlisting role="php">
+ <![CDATA[
+/**
+ * Performs a batch of database queries (atomically, not in transaction).
+ * @throws SQLException Low-level SQL errors will bubble up through this method.
+ */
+public function batchExecute();
+ ]]>
+ </programlisting>
+ </example>
+ </sect2>
+
+ <sect2>
+ <title>Exceptions as part of the API</title>
+
+ <para>
+ Exceptions play a critical role in the API of your
+ library. Developers using your library
+ <emphasis>depend</emphasis> on accurate descriptions of where
+ and why exceptions might be thrown from your
+ package. Documentation is critical. Also maintaining the types
+ of messages that are thrown is also an important requirement for
+ maintaining backwards-compatibility.
+ </para>
+ <para>
+ Because Exceptions are critical to the API of your package, you
+ must ensure that you don't break backwards compatibility (BC) by
+ making changes to exceptions.
+ </para>
+ <para>
+ Things that break BC include:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <simpara>
+ Any change to which methods throw exceptions.
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ A change whereby a method throws an exception higher in the
+ inheritance tree. For example, if you changed your method to
+ throw a <classname>PEAR_Exception</classname> rather than a
+ <classname>PEAR_IOException</classname>, you would be
+ breaking backwards compatibility.
+ </simpara>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Things that do not break BC:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <simpara>
+ Throwing a subclass of the original exception. For example,
+ changing a method to throw
+ <classname>PEAR_IOException</classname> when before it had
+ been throwing <classname>PEAR_Exception</classname> would
+ not break BC (provided that
+ <classname>PEAR_IOException</classname> extends
+ <classname>PEAR_Exception</classname>).
+ </simpara>
+ </listitem>
+ </itemizedlist>
+ </sect2>
+ </sect1>
+
+
<sect1 id="standards.bestpractices">
<title>Meilleure pratique</title>
<para>
--
PEAR Documentation List Mailing List (http://pear.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic