I have written this HTML static class which may categorize as a helper (not really sure what the definition of helper is). Anyways, I was just wondering if it was a smart idea to call a bunch of PHP functions instead of using raw markup because it just doesn't seem right to me.
One of the things that I'm positive about is that as output it creates a long string instead of many lines with tabs and line breaks (i.e. it is automatically minified). However, there's still this thing inside that's bugging me about these function calls because each element is a product of a function call, and this means that there will be a lot of calls, as opposed to a simple string output in ordinary case of raw markup.
This is an example usage:
echo \HTML::html(
\HTML::head(
\HTML::title('Hello')
)
.
\HTML::body(
\HTML::h1('Hello world').
\HTML::p('example')
)
);
And the result:
<html><head><title>Hello</title></head><body><h1>Hello world</h1><p>example</p></body></html>
In the actual usage I will not have concatenating strings like between head and body. I use a template engine and that's it's job, however now for the sake of simplicity I just use a concatenation.
The actual class itself:
/**
*
* Author php_nub_qq at stackoverflow.com
*
**/
final class HTML {
private function __construct() {
}
public static function __callStatic($name, $arguments) {
$content = isset($arguments[0]) ? $arguments[0] : null;
$attributes = isset($arguments[1]) ? $arguments[1] : array();
return '<'.$name.self::parseAttributes($attributes).'>'.$content.'</'.$name.'>';
}
public static function script($src, array $attributes = array(), $defer = true){
$attributes['type'] = 'text/javascript';
$attributes['src'] = strstr($src, '://') ? $src : SITE_URL . $src;
if($defer){
$attributes['defer'] = 'defer';
}
return '<script'.self::parseAttributes($attributes).'></script>';
}
public static function stylesheet($src, array $attributes = array()){
$attributes['type'] = 'text/css';
$attributes['href'] = strstr($src, '://') ? $src : SITE_URL . $src;
$attributes['rel'] = 'stylesheet';
return '<link'.self::parseAttributes($attributes).'/>';
}
public static function a($url, $text = null, $target = '_self', array $attributes = array()){
$attributes['href'] = strpos($url, '://') === false ? SITE_URL.$url : $url;
$attributes['target'] = $target;
if($text === null){
$text = $attributes['href'];
}
return '<a'.self::parseAttributes($attributes).'>'.$text.'</a>';
}
public static function form($method = 'GET', $action = '', array $attributes = array(), $csrfToken = null, $content = null){
if($csrfToken === null){
$csrfToken = \Input::generateCSRFtoken();
}
$attributes['method'] = $method;
$attributes['action'] = $action;
return '<form'.self::parseAttributes($attributes).'>'.
'<input type="hidden" name="csrf-token" value="'.$csrfToken.'"/>'.
$content.
'</form>';
}
public static function input($name, $type, $value = null, array $attributes = array(), $div = true){
$attributes['name'] = $name;
if($name === null){
$div = '';
}else{
if($value === null && $type != 'password'){
$value = \Input::data($name);
}
if($div){
$div = '<div class="'.$name.' Field-Error">'.\Input::getValidationErrors($name).'</div>';
}
}
switch($type){
case 'textarea':
$input = '<textarea'.self::parseAttributes($attributes).'>'.$value.'</textarea>';
break;
case 'select':
if(is_array($value)){
$options = '';
foreach($value as $key => $option){
$options .= '<option value="'.$key.'">'.$option.'</option>';
}
$input = '<select'.self::parseAttributes($attributes).'><option>'.$options.'</option></select>';
}
break;
default:
$attributes['type'] = $type;
$attributes['value'] = $value;
$input = '<input'.self::parseAttributes($attributes).'/>';
}
return $div.$input;
}
private static function parseAttributes($attributes){
foreach($attributes as $attribute => $value){
$attributes[$attribute] = ' '.$attribute . '="'.$value.'"';
}
return join('', $attributes);
}
public static function sanitize($string, $flag = ENT_QUOTES, $encoding = 'UTF-8'){
return htmlspecialchars($string, $flag, $encoding);
}
}
A few details - the __callStatic
function handles the majority of tags, and currently does not support self-closing tags. The whole class is currently a work in progress and I'd be really thankful if you share any bugs or improvements you see. I would like to also mention that if anyone finds this class useful they can use it freely (not that I can actually put any restrictions on that but just thought it's good to know).
Also about the sanitize
function, I know it's not good to create function wrappers that do nothing else than call another function with the same parameters, but that's just something I foresaw. Maybe in the future I will need to put some custom sanitizing technique or something, then I'll have all of my projects automatically updated, as opposed to having to start implementing it everywhere.
?>
, write the markup and reopen<?php
). Why add the overhead of static method calls and a pure evil magic__callStatic
? Your api doesn't allow me to turn back to a node, change some attributes or add children to it. In the end, I'm still stuck writing rather old-school procedural styled code (with an OO front) \$\endgroup\$