* @copyright (c) 2013, Christian Sciberras * @license https://raw.github.com/uuf6429/nice_r/master/LICENSE MIT License * @link https://github.com/uuf6429/nice_r GitHub Repository * @version 2.0 * @since 2.0 * @package Wsal */ class WSAL_Nicer { /** * Input string. * * @var mixed */ protected $value; /** * Allows modification of CSS class prefix. * * @var string */ public $css_class = 'nice_r'; /** * Allows modification of HTML id prefix. * * @var string */ public $html_id = 'nice_r_v'; /** * Allows modification of JS function used to toggle sections. * * @var string */ public $js_func = 'nice_r_toggle'; /** * Whether to inspect and output methods for objects or not. * * @var boolean */ public $inspect_methods = false; /** * Since PHP does not support private constants, we'll have to settle for private static fields. * * @var string */ protected static $BEEN_THERE = '__NICE_R_INFINITE_RECURSION_PROTECT__'; /** * True if ReflectionClass exists. * * @var bool */ protected $_has_reflection = null; /** * Constructs new renderer instance. * * @param mixed $value The value to inspect and render. * @param boolean $inspect_methods Whether to inspect and output methods for objects or not. */ public function __construct( $value, $inspect_methods = false ) { $this->value = $value; $this->inspect_methods = $inspect_methods; if ( is_null( $this->_has_reflection ) ) { $this->_has_reflection = class_exists( 'ReflectionClass' ); } } /** * Generates the inspector HTML and returns it as a string. * * @return string Generated HTML. */ public function generate() { return $this->_generate_value( $this->value, $this->css_class ); } /** * Renders the inspector HTML directly to the browser. */ public function render() { echo $this->generate(); } /** * Converts a string to HTML, encoding any special characters. * * @param string $text The original string. * @return string The string as HTML. */ protected function _esc_html( $text ) { return htmlspecialchars( $text, ENT_QUOTES, 'UTF-8' ); } protected function _inspect_array( &$html, &$var ) { $has_subitems = false; foreach ( $var as $k => $v ) { if ( $k !== self::$BEEN_THERE ) { $html .= $this->_generate_keyvalue( $k, $v ); $has_subitems = true; } } if ( ! $has_subitems ) { $html .= 'Empty Array'; } } protected function _inspect_object( &$html, &$var ) { // Render properties. $has_subitems = false; foreach ( (array) $var as $k => $v ) { if ( $k !== self::$BEEN_THERE ) { $html .= $this->_generate_keyvalue( $k, $v ); $has_subitems = true; } } if ( ! $has_subitems ) { $html .= 'No Properties'; } // Render methods (if enabled). if ( $this->inspect_methods ) { $has_subitems = false; foreach ( (array) get_class_methods( $var ) as $method ) { $html .= $this->_generate_callable( $var, $method ); $has_subitems = true; } if ( ! $has_subitems ) { $html .= 'No Methods'; } } } /** * Render a single particular value. * * @param mixed $var The value to render. * @param string $class Parent CSS class. * @param string $id Item HTML id. */ protected function _generate_value( $var, $class = '', $id = '' ) { $BEENTHERE = self::$BEEN_THERE; $class .= ' ' . $this->css_class . '_t_' . gettype( $var ); $html = '
'; switch ( true ) { // Handle arrays. case is_array( $var ): if ( isset( $var[ $BEENTHERE ] ) ) { $html .= 'Infinite Recursion Detected!'; } else { $var[ $BEENTHERE ] = true; $this->_inspect_array( $html, $var ); unset( $var[ $BEENTHERE ] ); } break; // Handle objects. case is_object( $var ): if ( isset( $var->$BEENTHERE ) ) { $html .= 'Infinite Recursion Detected!'; } else { $var->$BEENTHERE = true; $this->_inspect_object( $html, $var ); unset( $var->$BEENTHERE ); } break; // Handle simple types. default: $html .= $this->_generate_keyvalue( '', $var ); break; } return $html . '
'; } /** * Generates a new unique ID for tagging elements. * * @staticvar int $id * @return integer An ID unique per request. */ protected function _generate_dropid() { static $id = 0; return ++$id; } /** * Render a key-value pair. * * @staticvar int $id Specifies element id. * @param string $key Key name. * @param mixed $val Key value. */ protected function _generate_keyvalue( $key, $val ) { $id = $this->_generate_dropid(); $p = ''; // Preview $d = ''; // Description $t = gettype( $val ); // Get data type. $is_hash = ( 'array' == $t ) || ( 'object' == $t ); switch ( $t ) { case 'boolean': $p = $val ? 'TRUE' : 'FALSE'; break; case 'integer': case 'double': $p = (string) $val; break; case 'string': $d .= ', ' . strlen( $val ) . ' characters'; $p = $val; break; case 'resource': $d .= ', ' . get_resource_type( $val ) . ' type'; $p = (string) $val; break; case 'array': $d .= ', ' . count( $val ) . ' elements'; break; case 'object': $d .= ', ' . get_class( $val ) . ', ' . count( get_object_vars( $val ) ) . ' properties'; break; default: // fallback for any other types would go here break; } $cls = $this->css_class; $xcls = ! $is_hash ? $cls . '_ad' : ''; $html = ''; $html .= ' '; $html .= ' ' . $this->_esc_html( $key ) . ''; $html .= ' (' . ucwords( $t ) . '' . $d . ')'; $html .= ' ' . $this->_esc_html( $p ) . ''; $html .= ''; if ( $is_hash ) { $html .= $this->_generate_value( $val, $cls . '_v', $this->html_id . '_v' . $id ); } return $html; } protected function _generate_callable( $context, $callback ) { $id = $this->_generate_dropid(); $ref = null; $name = 'Anonymous'; $cls = $this->css_class; if ( $this->_has_reflection ) { if ( is_null( $context ) ) { $ref = new ReflectionFunction( $callback ); } else { $ref = new ReflectionMethod( $context, $callback ); } $name = $ref->getName(); } elseif ( is_string( $callback ) ) { $name = $callback; } if ( ! is_null( $ref ) ) { $doc = $ref->getDocComment(); $prms = array(); foreach ( $ref->getParameters() as $p ) { $prms[] = '$' . $p->getName() . ( $p->isDefaultValueAvailable() ? ( ' = ' . ( $p->isDefaultValueConstant() ? $p->getDefaultValueConstantName() : var_export( $p->getDefaultValue(), true ) ) . '' ) : '' ); } } else { $doc = null; $prms = array( '???' ); } $xcls = ! $doc ? $cls . '_ad' : ''; $html = ''; $html .= ' '; $html .= ' ' . $this->_esc_html( $name ) . '(' . implode( ', ', $prms ) . ')'; $html .= ''; if ( $doc ) { $html .= '
'; $html .= nl2br( str_replace( ' ', ' ', $this->_esc_html( $doc ) ) ); $html .= '
'; } return $html; } }