blob: 14852d84a0c567a26912e033f554fe7cd5047910 [file] [log] [blame]
<?php
/**
* File containing the ezcDebugVariableDumpTool class.
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package Debug
* @version //autogentag//
* @copyright Copyright (C) 2005-2010 eZ Systems AS. All rights reserved.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
*/
/**
* Tool class to dump variables in a way similar to Xdebug.
*
* This tool class allows to dump variables similar to the way it is done by
* Xdebug (@link http://xdebug.org). The class is used in the {@link
* ezcDebugPhpStacktraceIterator} to unify the variable dumps with those
* generated by {@link ezcDebugXdebugStacktraceIterator}.
*
* @package Debug
* @version //autogen//
*/
class ezcDebugVariableDumpTool
{
/**
* Returns the string representation of an variable.
*
* Returns the dump of the given variable, respecting the $maxData and
* $maxChildren paramaters when arrays or objects are dumped. $maxDepth is
* the maximum recursion depth when dumping arrays and objects.
*
* @param mixed $arg
* @param int $maxData
* @param int $maxChildren
* @param int $maxDepth
* @return string
*/
public static function dumpVariable( $arg, $maxData, $maxChildren, $maxDepth )
{
switch ( gettype( $arg ) )
{
case 'boolean':
return self::cutString( ( $arg ? 'TRUE' : 'FALSE' ), $maxData );
case 'integer':
case 'double':
return self::cutString( (string) $arg, $maxData );
case 'string':
return sprintf(
"'%s'",
self::cutString( (string) $arg, $maxData )
);
case 'array':
return self::dumpArray( $arg, $maxData, $maxChildren, $maxDepth );
case 'object':
return self::dumpObject( $arg, $maxData, $maxChildren, $maxDepth );
case 'resource':
return self::dumpResource( $arg, $maxData );
case 'NULL':
return 'NULL';
default:
return 'unknown type';
}
}
/**
* Returns the string representation of an array.
*
* Returns the dump of the given array, respecting the $maxData and
* $maxChildren paramaters.
*
* @param array $arg
* @param int $maxData
* @param int $maxChildren
* @param int $maxDepth
* @return string
*/
private static function dumpArray( array $arg, $maxData, $maxChildren, $maxDepth )
{
$arrayContent = '';
if ( $maxDepth !== 0 )
{
$max = (
$maxChildren === false
? count( $arg )
: min( count( $arg ), $maxChildren )
);
$results = array();
reset( $arg );
for ( $i = 0; $i < $max; ++$i )
{
$results[] =
self::dumpVariable(
key( $arg ),
$maxData,
$maxChildren,
( $maxDepth === false ? $maxDepth : $maxDepth - 1 )
)
. ' => '
. self::dumpVariable(
current( $arg ),
$maxData,
$maxChildren,
( $maxDepth === false ? $maxDepth : $maxDepth - 1 )
);
next( $arg );
}
if ( $max < count( $arg ) )
{
$results[] = '...';
}
$arrayContent = implode( ', ', $results );
}
else
{
$arrayContent = '...';
}
return sprintf(
'array (%s)', $arrayContent
);
}
/**
* Returns the string representation of an object.
*
* Returns the dump of the given object, respecting the $maxData,
* $maxChildren and $maxDepth paramaters.
*
* @param object $arg
* @param int $maxData
* @param int $maxChildren
* @param int $maxDepth
* @return string
*/
private static function dumpObject( $arg, $maxData, $maxChildren, $maxDepth )
{
$refObj = new ReflectionObject( $arg );
$objectContent = '';
if ( $maxDepth !== 0 )
{
$refProps = $refObj->getProperties();
$max = (
$maxChildren === false
? min( count( $refProps ), $maxChildren )
: count( $refProps )
);
$results = array();
reset( $refProps );
for( $i = 0; $i < $max; $i++ )
{
$refProp = current( $refProps );
$results[] = sprintf(
'%s $%s = %s',
self::getPropertyVisibility( $refProp ),
$refProp->getName(),
self::getPropertyValue(
$refProp,
$arg,
$maxData,
$maxChildren,
( $maxDepth === false ? $maxDepth : $maxDepth - 1 )
)
);
next( $refProps );
}
$objectContent = implode( '; ', $results );
}
else
{
$objectContent = '...';
}
return sprintf(
'class %s { %s }',
$refObj->getName(),
$objectContent
);
}
/**
* Returns the string representation of a resource.
*
* Returns the dump of the given resource, respecting the $maxData
* paramater.
*
* @param resource $res
* @param int $maxData
* @return string
*/
private static function dumpResource( $res, $maxData )
{
// @TODO: Ugly, but necessary.
// 'resource(5) of type (stream)'
preg_match( '(^Resource id #(?P<id>\d+)$)', (string) $res, $matches );
return sprintf(
'resource(%s) of type (%s)',
$matches['id'],
get_resource_type( $res )
);
}
/**
* Returns the $value cut to $length and padded with '...'.
*
* @param string $value
* @param int $length
* @return string
*/
private static function cutString( $value, $length )
{
if ( $length !== false && ( strlen( $value ) > ( $length - 3 ) ) )
{
return substr( $value, 0, ( $length - 3 ) ) . '...';
}
return $value;
}
/**
* Returns private, protected or public.
*
* Returns the visibility of the given relfected property $refProp as a
* readable string.
*
* @param ReflectionProperty $refProp
* @return string
*/
private static function getPropertyVisibility( ReflectionProperty $refProp )
{
$info = '%s %s = %s';
if ( $refProp->isPrivate() )
{
return 'private';
}
if ( $refProp->isProtected() )
{
return 'protected';
}
return 'public';
}
/**
* Returns the dumped property value.
*
* Returns the dumped value for the given reflected property ($refProp) on
* the given $obj. Makes use of the ugly array casting hack to determine
* values of private and protected properties.
*
* @param ReflectionProperty $refProp
* @param object $obj
* @param int $maxData
* @param int $maxChildren
* @param int $maxDepth
* @return string
*/
private static function getPropertyValue( ReflectionProperty $refProp, $obj, $maxData, $maxChildren, $maxDepth )
{
$value = null;
// @TODO: If we switch to PHP version 5.3, where Reflection can access
// protected/private property values, we should change this to the
// correct way.
if ( !$refProp->isPublic() )
{
$objArr = (array) $obj;
$className = ( $refProp->isProtected() ? '*' : $refProp->getDeclaringClass()->getName() );
$propName = $refProp->getName();
$value = $objArr["\0{$className}\0{$propName}"];
}
else
{
$value = $refProp->getValue( $obj );
}
return self::dumpVariable( $value, $maxData, $maxChildren, $maxDepth );
}
}
?>