UML for for C-I - <Code> - <PHPUnit Test>

abstract class SortFactory{  
  static public function Create( $index, $order = 'ascending' ){    
    switch( $index ){
      case 'gender' : return new SortGender( $order );
        break;
      case 'dob' : return new SortDate( $order );
        break;
      case 'lastName' : return new SortLastName( $order );
        break;
    }
  }/* End method Create() */  
}/* End class SortFactory */
                 
class PersonsList{
  private $_persons = array();
   
  public function __construct( $list ){
    $this->_persons = $list;
  }

  /* perform a sort using an implementation of iSort */
  public function sort( iSort $type ){
    $this->_persons = $type->sort( $this->_persons );
  }
  
  public function getList(){
    return $this->_persons;
  }
  /* display the persons as an HTML list */
  public function display( $caption = 'Initial List' ){
    echo '<table><tr><th>Last Name</th><th>First Name</th><th>Gender</th><th>Date of Birth</th><th>Favorite Color</th></tr>';
    echo '<caption>$caption</caption>';
    foreach( $this->_persons as $person ){
      echo "<tr><td>{$person['lastName']}</td><td>{$person['firstName']}</td><td>{$person['gender']}</td><td>{$person['dob']}</td><td>{$person['color']}</td></tr>";
    }
    echo '</table>';
  }
}/* End of class PersonsList */
                 
  interface iParse{
    public function parseFile();
  }
                
  abstract class ReadFile{
    protected $path  = TEXT_FILE_PATH;
    protected $file = '';
     
    public function __construct( $file = '' ){
      if( !empty( $file ) ){
        $this->file = $file;
      }else{
        throw  new Exception( 'No file name was provided.' );
      }
      $this->file = $this->path . $this->file;
      if( !file_exists( $this->file ) || !is_file( $this->file ) ){       
        throw new Exception( 'The file does not exist.' );
      }
    }/* End of constructor */
      
    public function readFile(){
      $this->file = file( $this->file  );
    }/* End of method readFile() */    
  }/* End of class ReadFile */
                
  class ReadPipeFile extends ReadFile implements iParse{
    protected $data = array();
      
    public function parseFile(){
      $cnt = 0;
      foreach( $this->file as $line ){
        $lineArray = explode( ' | ', $line );
        $this->data[$cnt]['lastName']  = $lineArray[0];
        $this->data[$cnt]['firstName'] = $lineArray[1];
        $this->data[$cnt]['mi']        = $lineArray[2];
        $this->data[$cnt]['gender']    = ( 'M' === $lineArray[3] ) ? 'Male' : 'Female';
        $this->data[$cnt]['color']     = $lineArray[4];
        $this->data[$cnt]['dob']       = str_replace( '-', '/', $lineArray[5] );
        $cnt++;
      }
    }/* End of method parseFile() */
  
    public function getData(){
      $this->readFile();
      $this->parseFile();
      return $this->data;
    }/* End of method getData */    
  }/* End of class ReadPipeFile */
                
  class ReadCommaFile extends ReadFile implements iParse{
    protected $data = array();
  
    public function parseFile(){
      $cnt = 0;
      foreach( $this->file as $line ){
        $lineArray = explode( ', ', $line );
        $this->data[$cnt]['lastName']  = trim($lineArray[0]);
        $this->data[$cnt]['firstName'] = trim($lineArray[1]);
        $this->data[$cnt]['gender']    = trim($lineArray[2]);
        $this->data[$cnt]['dob']       = trim($lineArray[4]);
        $this->data[$cnt]['color']     = trim($lineArray[3]);
        $cnt++;
      }
    }/* End of method parseFile() */
  
    public function getData(){
      $this->readFile();
      $this->parseFile();
      return $this->data;
    }/* End of method getData */    
  }/* End of class ReadCommaFile */
                
  class ReadSpaceFile extends ReadFile implements iParse{
    protected $data = array();
   
    public function parseFile(){
      $cnt = 0;
      foreach( $this->file as $line ){
        $lineArray = explode( ' ', $line );
        $this->data[$cnt]['lastName']  = trim($lineArray[0]);
        $this->data[$cnt]['firstName'] = trim($lineArray[1]);
        $this->data[$cnt]['gender']    = ( 'M' === $lineArray[3] ) ? 'Male' : 'Female';
        $this->data[$cnt]['color']     = trim($lineArray[5]);
        $this->data[$cnt]['dob']       = trim(str_replace( '-', '/', $lineArray[4] ));
        $cnt++;
      }
    }/* End of method parseFile() */
  
    public function getData(){
      $this->readFile();
      $this->parseFile();
      return $this->data;
    }/* End of method getData */    
  }/* End of class ReadSpaceFile */
                
interface iSort{
  public function sort( array $list );
}
                 
abstract class SortData{
  /* how to sort */
  protected $order = '';
 
  public function __construct( $order = 'ascending' ){
    $this->order = $order;
  }
  public function sort( array $list ){
    /* change the algorithm to match the sort preference */
    if( 'ascending' === $this->order ){
      uasort( $list, array( $this, 'ascSort' ) );
    }else{
      uasort( $list, array( $this, 'descSort' ) );
    }
    return $list;
  }
  abstract protected function ascSort( $x, $y );

  abstract protected function descSort( $x, $y );

}/* End of class SortLastName(); */
                 
class SortDate extends SortData implements iSort{
  /* sort index */
  protected $index = 'dob';
  
  protected function ascSort( $x, $y ){
    $sort_order = strtotime($x[$this->index]) - strtotime($y[$this->index]);
    if( 0 < $sort_order){
      return true;
    }else if( 0 > $sort_order ){
      return false;
    }else{
      return $this->sortLastName( $x, $y );
    }
  }

  protected function descSort( $x, $y ){
    $sort_order = strtotime($y[$this->index]) - strtotime($x[$this->index]);
    if( 0 < $sort_order){
      return true;
    }else if( 0 > $sort_order ){
      return false;
    }else{
      return $this->sortLastName( $x, $y );
    }
  }

  private function sortLastName( $x, $y ){
    return strcasecmp( $x['lastName'], $y['lastName'] );
  }
}/* End of class SortDate */
                 
class SortGender extends SortData implements iSort{
  /* sort index */
  protected $index = 'gender';
 
  protected function ascSort( $x, $y ){
    $sort_order = strcasecmp( $x[$this->index], $y[$this->index] );
    if( 0 < $sort_order){
      return true;
    }else if( 0 > $sort_order ){
      return false;
    }else{
      return $this->sortLastName( $x, $y );
    }
  }

  protected function descSort( $x, $y ){
    return strcasecmp( $y[$this->index], $x[$this->index] );
  }

  private function sortLastName( $x, $y ){
    return strcasecmp( $x['lastName'], $y['lastName'] );
  }
}/* End of class SortGender */
                 
class SortLastName extends SortData implements iSort{
  /* sort index */
  protected $index = 'lastName';

  protected function ascSort( $x, $y ){
    return strcasecmp( $x[$this->index], $y[$this->index] );
  }

  protected function descSort( $x, $y ){
    return strcasecmp( $y[$this->index], $x[$this->index] );
  }
}/* End of class SortLastName(); */