Well, almost…
text = $text; } function toString() { return $this->text; } } function squash_attribs($attribs) { return implode(' ', array_map('squash_attrib', array_keys($attribs), array_values($attribs))); } function squash_attrib($key, $value) { return htmlspecialchars($key) . '="' . htmlspecialchars($value) . '"'; } function xx() { $args = func_get_args(); $name = array_shift($args); $next = array_shift($args); if (is_array($next)) { $attribs = ' ' . squash_attribs($next); $next = array_shift($args); } else { $attribs = ''; } $contents = null; while (null !== $next) { if (is_object($next)) { $contents .= $next->toString(); } else { $contents .= htmlspecialchars( $next ); } $next = array_shift($args); } if ($contents === null) { return new XmlFragment("<$name$attribs />"); } else { return new XmlFragment("<$name$attribs>$contents$name>"); } } $page = xx("html", array("lang" => "en"), xx("body", xx("h1", "Some thingy"), xx("p", "This & that. Nothing important..."), xx("hr"), xx("h2", "Log in"), xx("form", array("method" => "post", "action" => "/submit.php"), xx("label", array("for" => "user"), "Username:"), " ", xx("input", array("name" => "user")), xx("br"), xx("label", array("for" => "password"), "Password:"), " ", xx("input", array("name" => "password", "type" => "password")), xx("br"), xx("input", array("type" => "submit"))), xx("hr"), xx("p", "That's, folks!"))); echo $page->toString(); ?>