code: static public function table( $rows, $headertype = 'keys', $footertype = 'none', $empty_row_string = 'No Data' ) {
          
          if( !@count( $rows ) ) {
              
              if( $empty_row_string !== null ) {
                  $rows = [ [ $empty_row_string ] ];
              }
              else {
                  return '';
              }
          }
  
          $header = null;
          if( $headertype == 'keys' ) {        
              $header = array_keys( static::obj_arr( $rows[0] ) );
          }
          else if( $headertype == 'firstrow' ) {
              $header = static::obj_arr( array_shift( $rows ) );
          }
          
          $col_widths = array();
          
          static::calc_row_col_widths_and_align( $col_widths, $align, $header );
          foreach( $rows as $row ) {
              $row = static::obj_arr( $row );
              static::calc_row_col_widths_and_align( $col_widths, $align, $row );
          }
          
          $buf  = static::print_row( $col_widths, $align, $header );
          $buf .= static::print_divider_row( $col_widths, $align );
          foreach( $rows as $row ) {
              $row = static::obj_arr( $row );
              $buf .= static::print_row( $col_widths, $align, $row );
          }
          
          return $buf;
      }
docs: Formats a fixed-width text table, with borders.
  
  @param $rows  array of rows.  each row contains table cells.
  @param $headertype  keys | firstrow
  @param $empty_row_string  String to use when there is no data, or null.