[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
+        &quot;One True Path&quot; -- 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
+        &quot;eject!&quot; 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 &lt;Package_Name&gt;_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