library/My/Html/Element/Abstract.php:

<?php
	/**
	 *
	 */

	/**
	 * Class from which every html should be extended
	 * 
	 * @abstract
	 */
	abstract class My_Html_Element_Abstract {
		
		/**
		 * Are the elements defined in XHTML?
		 * @static
		 * @var	bool
		 */
		protected static $_xhtml = true;
		
		/**
		 * Set/get whether xhtml will be used
		 * 
		 * @param	bool|null	$bool
		 *
		 * @return	void|bool
		 */
		public static function xhtml ( $bool = null ) {
			
			if ( $bool === null ) {
				return self::$_xhtml;
				
			}
			
			self::$_xhtml = (bool)$bool;
		
		}
		
		/**
		 * Holds all the attributes for this element.
		 * @var	array
		 */
		protected $_attribs = array ();
		
		/**
		 * Class constructor
		 *
		 * @param	array	$attribs
		 */
		public function __construct ( array $attribs = array () ) {
			
			if ( count ( $attribs ) ) {
				$this->setAttribs ( $attribs );
				
			}
		
		}
		
		/**
		 * Try to render the element
		 *
		 * @return	string
		 */
		public function __toString () {
			
			try {
				return $this->render ();
				
			} catch ( Exception $e ) {
				return '';
				
			}
			
		}
		
		/**
		 * The method for rendering
		 *
		 * @abstract
		 *
		 * @return	string
		 */
		public abstract function render ();
		
		/**
		 * Set an attribute
		 *
		 * @param	string	$attrib
		 * @param	string 	$value
		 *
		 * @return 	My_Html_Element_Abstract
		 */
		public function setAttrib ( $attrib, $value ) {
			$this->_attribs [ $attrib ] = $value;
			
			return $this;
			
		}
		
		/**
		 * Set attributes
		 *
		 * @param	array	$attribs
		 *
		 * @return	My_Html_Element_Abstract
		 */
		public function setAttribs ( $attribs ) {
			$this->_attribs = array_merge ( $this->_attribs, $attribs );
			
			return $this;
			
		}
		
		/**
		 * Has this elment an attribute?
		 *
		 * @param	string	$attrib
		 *
		 * @return	bool
		 */
		public function hasAttrib ( $attrib ) {
			return array_key_exists ( $attrib, $this->_attribs );
			
		}
		
		/**
		 * Method for rendering the attribute string
		 *
		 * @param	array	$extras	OPTIONAL
		 *
		 * @return	string
		 */
		protected function _attribString ( array $extras = array () ) {
			
			// First initialize
			$return = array ();
			$attribs = $this->_attribs;
			
			// Maybe some extra attributes were given
			foreach ( $extras as $attrib => $value ) {
				
				if ( empty ( $value ) ) {
					continue;
					
				}
				
				// Maybe special functions are used? (+, -)
				$first = substr ( $attrib, 0, 1 );
				$key = substr ( $attrib, 1 );
				
				// Switch on special function
				switch ( $first ) {
					case '+':	// Append this new value to the current value
						
						if ( isset ( $attribs [ $key ] ) ) {
							$attribs [ $key ] .= ' ' . $value;
							
						} else {
							$attribs [ $key ] = $value;
							
						}
						
						break;
					
					case '-':	// Remove this new value from the current value
						
						if ( isset ( $attribs [ $key ] ) ) {
							$exploded = explode ( ' ', $attribs [ $key ] );
							
							foreach ( $exploded as $k => $v ) {
								
								if ( $v === $value ) {
									unset ( $exploded [ $k ] );
									
								}
								
							}
							
							$attribs [ $key ] = implode ( ' ', $exploded );
							
						}
						
						break;
					
					default:	// Just set the value
						$attribs [ $attrib ] = $value;
					
				}
				
			}
			
			// Render the string
			foreach ( $attribs as $attrib => $value ) {
				
				if ( $value === null ) {
					continue;
					
				}
				
				$return [] = $attrib . '=' . '"' . htmlentities ( $value ) . '"';
				
			}
			
			// Return nothing on empty, else separated by spaces
			if ( count ( $return ) === 0 ) {
				return  '';
				
			} else {
				return ' ' . implode ( ' ', $return );
				
			}
			
		}
		
	}
?>

library/My/Html/Element/Table.php:
<?php
	/**
	 *
	 */
	
	/**
	 * Base class for the table element
	 */
	class My_Html_Element_Table extends My_Html_Element_Abstract implements IteratorAggregate, Countable, ArrayAccess {
		
		const TAG = 'table';
		
		/**
		 * The head element
		 * @var	My_Html_Element_THead
		 */
		protected $_head;
		
		/**
		 * The body element
		 * @var	My_Html_Element_TBody
		 */
		protected $_body;
		
		/**
		 * Class constructor
		 *
		 * @param	array	$rows
		 * @param	array	$attribs
		 *
		 * @return	void
		 */
		public function __construct ( array $rows = array (), array $attribs = array () ) {
			parent::__construct ( $attribs );
			
			$this->addRows ( $rows );
			
		}
		
		/**
		 * Overloads to body when possible
		 *
		 * @param	string	$method
		 * @param	array	$argumentsS
		 *
		 * @return	mixed
		 */
		public function __call ( $method, array $arguments ) {
			
			// Check if method exists in the body, if so proxy to it.
			if ( method_exists ( $this->getBody (), $method ) ) {
				$result = call_user_func_array ( array ( $this->getBody (), $method ), $arguments );
				
				// Maybe the method had a fluent interface, make sure we redirect to this object
				return ($result instanceof My_Html_Element_TBody) ? $this : $result;
					
			}
			
			trigger_error ( 'Call to undefined method ' . get_class ( $this ) . '::' . $method . '()', E_USER_ERROR );
			
		}
		
		/**
		 * Returns the head element of this table.
		 *
		 * @return	My_Html_Element_THead
		 */
		public function getHead () {
			
			if ( $this->_head === null ) {
				$this->_head = new My_Html_Element_THead;
				
			}
			
			return $this->_head;
			
		}
		
		/**
		 * If instance of THead, it sets the head value of this class
		 * else it proxies to THead::setRow
		 *
		 * @param	My_Html_Element_THead|My_Html_Element_TR|array	$head
		 *
		 * @return	My_Html_Element_Table
		 */
		public function setHead ( $head ) {
			
			if ( $head instanceof My_Html_Element_THead ) {
				$this->_head = $head;
			
			} else {
				$this->getHead ()->setRow ( $head );
				
			}
			
			return $this;
			
		}
		
		/**
		 * Returns the body element of this table.
		 *
		 * @return	My_Html_Element_TBody
		 */
		public function getBody () {
			
			if ( $this->_body === null ) {
				$this->_body = new My_Html_Element_TBody;
				
			}
			
			return $this->_body;
			
		}
		
		/**
		 * Sets the body element of this table.
		 *
		 * @param	My_Html_Element_TBody	$body
		 *
		 * @return	My_Html_Element_Table
		 */
		public function setBody ( My_Html_Element_TBody $body ) {
			$this->_body = $body;
			
			return $this;
			
		}
		
		/**
		 * Returns the element as a string
		 *
		 * @return	string
		 */
		public function render () {
			
			$return = '<' . self::TAG . $this->_attribString () . '>';
			$return .= PHP_EOL;
			
			$return .= $this->getHead ()->render ();
			$return .= PHP_EOL;
			
			$return .= $this->getBody ()->render ();
			$return .= PHP_EOL;
			
			$return .= '</' . self::TAG . '>';
			
			return $return;
			
		}
		
		// INTERFACES
		
		/**
		 * IteratorAggregate implementation
		 *
		 * @return	Iterator
		 */
		public function getIterator () {
			return $this->getBody ()->getIterator ();
			
		}
		
		/**
		 * Countable implementation
		 *
		 * @return	int
		 */
		public function count () {
			return count ( $this->getBody () );
			
		}
		
		/**
		 * Partial ArrayAccess implementation
		 *
		 * @return	My_Html_Element_TR
		 */
		public function offsetGet ( $offset ) {
			return $this->getBody ()->offsetGet ( $offset );
			
		}
		
		/**
		 * Partial ArrayAccess implementation
		 *
		 * @return	void
		 */
		public function offsetSet ( $offset, $value ) {
			$this->getBody ()->offsetSet ( $offset );
			
		}
		
		/**
		 * Partial ArrayAccess implementation
		 *
		 * @return	bool
		 */
		public function offsetExists ( $offset ) {
			return $this->getBody ()->offsetExists ( $offset );
			
		}
		
		/**
		 * Partial ArrayAccess implementation
		 *
		 * @return	void
		 */
		public function offsetUnset ( $offset ) {
			$this->getBody ()->offsetUnset ( $offset );
		
		}
		
	}
?>

library/My/Html/Element/THead.php:
<?php
	/**
	 *
	 */
	
	/**
	 * Base class for the thead element
	 */
	class My_Html_Element_THead extends My_Html_Element_Abstract {
		
		const TAG = 'thead';
		
		/**
		 * Holds the row for thead element
		 * @var	My_Html_Element_TR
		 */
		protected $_row = null;
		
		/**
		 * Class constructor
		 *
		 * @return	void
		 */
		public function __construct () {
			$this->_row = new My_Html_Element_TR ( array (), true );
			
		}
		
		/**
		 * Set the row values for this element
		 *
		 * @param	My_Html_Element_TR|array	$row
		 *
		 * @return My_Html_Element_THead
		 */
		public function setRow ( $row ) {
			
			if ( $row instanceof My_Html_Element_TR ) { 
				$this->_row = $row;
			
			} elseif ( is_array ( $row ) ) {
				$this->_row->setCells ( $row );
				
			} else {
				throw new InvalidArgumentException ( gettype ( $row ) . ' given where array or instanceof My_Html_Element_TR expected' );
				
			}
			
			return $this;
			
		}
		
		/**
		 * Returns the row for this element
		 *
		 * @return	My_Html_Element_TR
		 */
		public function getRow () {
			
			if ( $this->_row === null ) {
				$this->_row = new My_Html_Element_TR;
				
			}
			
			return $this->_row;
			
		}
		
		/**
		 * Returns this element as a string
		 *
		 * @return	string
		 */
		public function render () {
			
			$return = '<' . self::TAG . $this->_attribString () . '>';
			$return .= PHP_EOL;
			
			$return .= $this->getRow ()->render ();
			$return .= PHP_EOL;
			
			$return .= '</' . self::TAG . '>';
			
			return $return;
			
		}
		
	}
?>

library/My/Html/Element/TR.php:
<?php
	/**
	 *
	 */
	
	/**
	 * Base class for the tr element
	 */
	class My_Html_Element_TR extends My_Html_Element_Abstract implements IteratorAggregate, Countable, ArrayAccess {
		
		const TAG = 'tr';
		
		/**
		 * Holds the cells
		 * @var	array
		 */
		protected $_cells = array ();
		
		/**
		 * The class which this class excepts as cell element
		 * @var	string
		 */
		protected $_accept = 'My_Html_Element_TD';
		
		/**
		 * Class constructor
		 *
		 * @param	array	$cells
		 * @param	bool	$head	Is this tr part of THead?
		 */
		public function __construct ( array $cells = array (), $head = false ) {
			
			if  ( $head ) {
				$this->_accept = 'My_Html_Element_TH';
				
			}
			
			$this->setCells ( $cells );
			
		}
		
		/**
		 * Get a cell
		 *
		 * @param	int	$cell
		 *
		 * @return My_Html_Element_TD|My_Html_Element_TH
		 */
		public function getCell ( $cell ) {
			
			if ( !isset ( $this->_cells [ $cell ] ) ) {
				throw new OutOfBoundsException ( 'Offset does not exist' );
				
			}
			
			return $this->_cells [ $cell ];
			
		}
		
		/**
		 * Set a cell
		 *
		 * @param	int	$cell
		 * @param	My_Html_Element_TD|My_Html_Element_TH	$value
		 *
		 * @return My_Html_Element_TR
		 */
		public function setCell ( $cell, $value ) {
			$this->_cells [ $cell ] = $value;
			
			return $this;
			
		}
		
		/**
		 * Set multiple cells
		 * 
		 * @param	array	$cells
		 *
		 * @return	My_Html_Element_TR
		 */
		public function setCells ( array $cells ) {
			
			$store = array ();
			foreach ( $cells as $cell ) {
				
				if ( is_object ( $cell ) && get_class ( $cell ) === $this->_accept ) {
					throw new RuntimeException ( 'Cell should be of type ' . $this->_accept );
					
				} elseif ( is_object ( $cell ) ) {
					$store [] = $cell;
					
				} else {
					$store [] = new $this->_accept ( $cell );
					
				}
			
			}
				
			$this->_cells = $store;
			
			return $this;
		}
		
		/**
		 * Returns this element as a string
		 *
		 * @return	string
		 */
		public function render () {
			
			$args = func_get_args ();
			$class = isset ( $args [ 0 ] ) && is_string ( $args [ 0 ] ) ? $args [ 0 ] : '';
			
			$return = '<' . self::TAG . $this->_attribString ( array ( '+class' => $class ) ) . '>';
			$return .= PHP_EOL;
			
			foreach ( $this as $cell ) {
				$return .= $cell->render ();
				$return .= PHP_EOL;
			
			}
			
			$return .= '</' . self::TAG . '>';
			
			return $return;
			
		}
		
		// INTERFACES
		
		/**
		 * IteratorAggregate implementation
		 *
		 * @return	Iterator
		 */
		public function getIterator () {
			return new ArrayIterator ( $this->_cells );
			
		}
		
		/**
		 * Countable implementation
		 *
		 * @return	int
		 */
		public function count () {
			return count ( $this->_cells );
			
		}
		
		/**
		 * Partial ArrayAccess implementation
		 *
		 * @return	My_Html_Element_TR
		 */
		public function offsetGet ( $offset ) {
			return $this->getCell ( $offset );
			
		}
		
		/**
		 * Partial ArrayAccess implementation
		 *
		 * @return	void
		 */
		public function offsetSet ( $offset, $value ) {
			$this->_cells [ $offset ] = $value;
			
		}
		
		/**
		 * Partial ArrayAccess implementation
		 *
		 * @return	bool
		 */
		public function offsetExists ( $offset ) {
			
			try { 
				$this->getCell ( $offset );
				
			} catch ( Exception $e ) {
				return false;
			
			}
			
			return true;
			
		}
		
		/**
		 * Partial ArrayAccess implementation
		 *
		 * @return	void
		 */
		public function offsetUnset ( $offset ) {
			unset ( $this->_cells [ $offset ] );
		
		}
		
	}
?>

library/My/Html/Element/TH.php:
<?php
	/**
	 *
	 */
	
	/**
	 * Base class for the th element
	 */
	class My_Html_Element_TH extends My_Html_Element_Abstract {
		
		const TAG = 'th';
		
		/**
		 * Holds the value of this element
		 * @var	string
		 */
		protected $_value;
		
		/**
		 * Class constructor
		 *
		 * @param	string	$value OPTIONAL
		 *
		 * @return	void
		 */
		public function __construct ( $value = null ) {
			$this->_value = $value;
			
		}
		
		/**
		 * Returns the value of this element
		 *
		 * @return	string
		 */
		public function getValue () {
			return $this->_value;
			
		}
		
		/**
		 * Sets the value of this element
		 *
		 * @param	string	$value
		 *
		 * @return	My_Html_Element_TD
		 */
		public function setValue ( $value ) {
			$this->_value = $value;
			
			return $this;
			
		}
		
		/**
		 * Returns this element as a string
		 *
		 * @return	string
		 */
		public function render () {
			
			$return = '<' . self::TAG . $this->_attribString () . '>';
			
			$return .= $this->getValue ();
			
			$return .= '</' . self::TAG . '>';
			
			return $return;
			
		}
		
	}
?>

library/My/Html/Element/TBody.php:
<?php
	/**
	 *
	 */
	
	/**
	 * Base class for the tbody element
	 */
	class My_Html_Element_TBody extends My_Html_Element_Abstract implements IteratorAggregate, Countable, ArrayAccess {
		
		const TAG = 'tbody';
		
		/**
		 * Holds the classes for rows
		 * @var	array
		 */
		protected $_rowClasses = array ();
		
		/**
		 * Holds the rows of this body.
		 * @var	array
		 */
		protected $_rows = array ();
		
		/**
		 * Class constructor
		 *
		 * @param	array	$rows
		 * @param	array	$attribs 
		 *
		 * @return	void
		 */
		public function __construct ( array $rows = array (), array $attribs = array () ) {
			parent::__construct ( $attribs );
			
		}
		
		/**
		 * Returns the row classes for this table.
		 *
		 * @return	array
		 */
		public function getRowClasses () {
			return $this->_rowClasses;
			
		}
		
		/**
		 * Sets the row classes for this table.
		 *
		 * @param	array	$classes
		 *
		 * @return 	My_Html_Element_Table
		 */
		public function setRowClasses ( array $classes ) {
			$this->_rowClasses = $classes;
			
			return $this;
			
		}		 
		
		/**
		 * Adds a new row
		 *
		 * @param	My_Html_Element_TR|array	$row
		 *
		 * @return	My_Html_Element_TBody
		 */
		public function addRow ( $row ) {
			
			if ( $row instanceof My_Html_Element_TR ) {
				$this->_rows [] = $row;
				
			} elseif ( is_array ( $row ) ) {
				$this->_rows [] = new My_Html_Element_TR ( $row );
				
			} else {
				throw new InvalidArgumentException ( gettype ( $row ) . ' given where array or instanceof My_Html_Element_TR expected' );
				
			}
			
			return $this;
			
		}
		
		/**
		 * Adds rows
		 *
		 * @param	array	$rows
		 *
		 * @return	My_Html_Element_TBody
		 */
		public function addRows ( array $rows ) {
			
			foreach ( $rows as $row ) {
				$this->addRow ( $row );
				
			}
			
			return $this;
			
		}
		
		/**
		 * Removes a row
		 *
		 * @param	My_Html_Element_TR|int	$row
		 *
		 * @return	My_Html_Element_TBody
		 */
		public function removeRow ( $row ) {
			
			// Make sure we have a My_Html_Element_TR
			$row = $this->getRow ( $row );
			
			foreach ( $this->_rows as $key => $r ) {
				
				if ( $row === $r ) {
					unset ( $this->_rows [ $key ] );
					
				}
				
			}
			
			return $this;
			
		}
		
		/**
		 * Returns the given row for this index
		 *
		 * @param	My_Html_Element_TR|int	$row
		 *
		 * @return	My_Html_Element_TR
		 */
		public function getRow ( $tr ) {
			
			if ( $tr instanceof My_Html_Element_TR ) {
				return $tr;
				
			} elseif ( ctype_digit ( (string)$tr ) ) {
				
				if ( !isset ( $this->_rows [ $tr ] ) ) {
					throw new OutOfRangeException ( 'Index not set' );
					
				}
				
				return $this->_rows [ $tr ];
				
			} else {
				throw new InvalidArgumentException ( 'Row type not supported' );
				
			}
			
		}
		
		/**
		 * Returns all the rows in this element
		 *
		 * @returns	array
		 */
		public function getRows () {
			return $this->_rows;
			
		}
		
		/**
		 * Returns this element as a string
		 *
		 * @return	string
		 */
		public function render () {
			
			$return = '<' . self::TAG . $this->_attribString () . '>';
			$return .= PHP_EOL;
			
			$classCount = count ( $this->_rowClasses );
			
			foreach ( $this as $key => $row ) {
				$return .= $classCount > 0 ? $row->render ( $this->_rowClasses [ $key % $classCount ] ) : $row->render ();
				$return .= PHP_EOL;
			
			}
			
			$return .= '</' . self::TAG . '>';
			
			return $return;
			
		}
		
		// INTERFACES
		
		/**
		 * IteratorAggregate implementation
		 *
		 * @return	Iterator
		 */
		public function getIterator () {
			return new ArrayIterator ( $this->_rows );
			
		}
		
		/**
		 * Countable implementation
		 *
		 * @return	int
		 */
		public function count () {
			return count ( $this->_rows );
			
		}
		
		/**
		 * Partial ArrayAccess implementation
		 *
		 * @return	My_Html_Element_TR
		 */
		public function offsetGet ( $offset ) {
			return $this->getRow ( $offset );
			
		}
		
		/**
		 * Partial ArrayAccess implementation
		 *
		 * @return	void
		 */
		public function offsetSet ( $offset, $value ) {
			$this->_rows [ $offset ] = $value;
			
		}
		
		/**
		 * Partial ArrayAccess implementation
		 *
		 * @return	bool
		 */
		public function offsetExists ( $offset ) {
			
			try { 
				$this->getRow ( $offset );
				
			} catch ( Exception $e ) {
				return false;
			
			}
			
			return true;
			
		}
		
		/**
		 * Partial ArrayAccess implementation
		 *
		 * @return	void
		 */
		public function offsetUnset ( $offset ) {
			unset ( $this->_rows [ $offset ] );
		
		}
		
	}
?>

library/My/Html/Element/TD.php:
<?php
	/**
	 *
	 */
	
	/**
	 * Base class for the td element
	 */
	class My_Html_Element_TD extends My_Html_Element_Abstract {
		
		const TAG = 'td';
		
		/**
		 * Holds the value of this element
		 * @var	string
		 */
		protected $_value;
		
		/**
		 * Class constructor
		 *
		 * @param	string	$value OPTIONAL
		 *
		 * @return	void
		 */
		public function __construct ( $value = null ) {
			$this->_value = $value;
			
		}
		
		/**
		 * Returns the value of this element
		 *
		 * @return	string
		 */
		public function getValue () {
			return $this->_value;
			
		}
		
		/**
		 * Sets the value of this element
		 *
		 * @param	string	$value
		 *
		 * @return	My_Html_Element_TD
		 */
		public function setValue ( $value ) {
			$this->_value = $value;
			
			return $this;
			
		}
		
		/**
		 * Returns this element as a string
		 *
		 * @return	string
		 */
		public function render () {
			
			$return = '<' . self::TAG . $this->_attribString () . '>';
			
			$return .= $this->getValue ();
			
			$return .= '</' . self::TAG . '>';
			
			return $return;
			
		}
		
	}
?>

index.php:
<?php
	require_once 'library/My/Html/Element/Abstract.php';
	require_once 'library/My/Html/Element/Table.php';
	require_once 'library/My/Html/Element/THead.php';
	require_once 'library/My/Html/Element/TR.php';
	require_once 'library/My/Html/Element/TH.php';
	require_once 'library/My/Html/Element/TBody.php';
	require_once 'library/My/Html/Element/TD.php';
	
	$table = new My_Html_Element_Table ( array (
						array ( 'alkd', ' dddd' ),
						array ( 'adf333', 'dd' ),
						array ( 'asdfkasdf', 'dd' )
					) );
					
	$table->setAttrib ( 'id', 'bla' )
		  ->setHead ( array ( 'col1', 'col2', 'col3' ) )
		  ->addRow ( array ( 'test', 'test', 'test' ) )
		  ->setRowClasses ( array ( 'odd', 'even', 'drie' ) );
		  
	$table->getBody ()->setAttrib ( 'id', 'kkkkk' );
	
	$table [ 1 ] [ 0 ]->setAttrib ( 'id', 'blaaaa' );
	$table->getBody ()->getRow ( 0 )->setAttrib ( 'class', 'test-class' );
	
	echo $table;			
	
	foreach ( $table as $row ) {
		
		foreach ( $row as $cell ) {
			echo $cell->getValue () . ', ';
			
		}
		
		echo '<br />';
		
	}
?>