title: How to handle business logic errors effectively?
body: <p>Let's suppose we have some objects hierarchy built via composition. Is there any pattern to register business logic errors within inner objects and pass them to the upper objects ?</p>
  
  <p>I am just tired of all these <em>addErrors</em>, <em>getErrors</em> on each level and I feel that I do something incorrectly.</p>
  
  <p>I know about exceptions, but I have no mind how to use them in such case. Business logic error is technically not a critical situation, which should result in interruption of the program execution. Actually interruption is not supposed at all, because we need to register the error and just move on.</p>
  
  <p><em>Thanks in advance to share your wisdom and knowledge )</em></p>
  
  <p>Small snippet to illustrate the problem:</p>
  
  <pre><code>class ErrorContainer {
      private $errors = array();
      function addError($error) { if (!is_array($error)) { $this-&gt;errors[] = $error;} else { $this-&gt;errors = array_merge($this-&gt;errors, $error); } }
      function getErrors() { return $this-&gt;errors[]; }
      function hasErrors() { return !empty($this-&gt;errors); }
  }
  
  class Processor extends ErrorContainer {
      function process($account_id, $orders) {
          $account = new Account();
          if (!$account-&gt;loadById($account_id)) { $this-&gt;addErrors($account-&gt;getErrors);}
  
          foreach ($orders as $order_id) {
              $order = new Order();
              if (!$order-&gt;loadById($order_id)) { $this-&gt;addErrors($order-&gt;getErrors);}
          }
      }
  
      return $this-&gt;hasErrors();
  }
  
  class Account extends ErrorContainer {
      function loadById($account_id) {
          $account = select_from_database($account_id);
          if (!$account) { $this-&gt;addError("Account is missing"); }
          if (!$account['active']) { $this-&gt;addError("Account is inactive"); }
          // and so on, some checks may add errors in a cycle
  
          return $this-&gt;hasErrors();
      }
  }
  
  class Order extends ErrorContainer {} // very similar to Account, but has its own checks
  
  //Usage:
  
  $errors = array();
  $items = load_items_from_xml($xml);
  foreach ($items as $item) {
      $processor = new Processor();
      if (!$processor-&gt;process($item['account_id'], $item['orders'])) {
          $errors = array_merge($errors, $processor-&gt;getErrors());
      }
  }
  </code></pre>