我正在使用MVC framework Symfony,似乎我要调试的很多内置对象都有循环引用。这使得无法使用print_r()
或var_dump()
打印变量(因为它们无限制地遵循循环引用,或者直到流程耗尽内存,以先到者为准)。
不是用自己的智慧编写自己的print_r
克隆,而是有更好的选择吗?我只希望能够将变量(对象,数组或标量)打印到日志文件,http标头或网页本身。
编辑:要澄清问题所在,请尝试以下代码:
<?php
class A
{
public $b;
public $c;
public function __construct()
{
$this->b = new B();
$this->c = new C();
}
}
class B
{
public $a;
public function __construct()
{
$this->a = new A();
}
}
class C
{
}
ini_set('memory_limit', '128M');
set_time_limit(5);
print_r(new A());
#var_dump(new A());
#var_export(new A());
它不适用于print_r()
,var_dump()
或var_export()
。错误消息是:
PHP致命错误:第10行的print_r_test.php中允许的内存大小为134217728字节(尝试分配523800字节)
答案 0 :(得分:14)
Doctrine具有相同的服务类。
使用示例:
<?php echo "<pre>"; \Doctrine\Common\Util\Debug::dump($result, 4); echo "</pre>";?>
答案 1 :(得分:12)
我们正在使用PRADO框架,它有一个名为“TVarDumper”的内置类,可以很好地处理这些复杂的对象 - 它甚至可以用漂亮的HTML格式来格式化它。语法突出显示。你可以从HERE获得该课程。
答案 2 :(得分:5)
TVarDumper旨在取代错误的PHP函数var_dump
和print_r
,因为它可以正确识别复杂对象结构中的递归引用对象。它还具有递归深度控制,以避免无限递归显示某些特殊变量。
<?php
/**
* TVarDumper class file
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.pradosoft.com/
* @copyright Copyright © 2005-2013 PradoSoft
* @license http://www.pradosoft.com/license/
* @version $Id$
* @package System.Util
*/
/**
* TVarDumper class.
*
* TVarDumper is intended to replace the buggy PHP function var_dump and print_r.
* It can correctly identify the recursively referenced objects in a complex
* object structure. It also has a recursive depth control to avoid indefinite
* recursive display of some peculiar variables.
*
* TVarDumper can be used as follows,
* <code>
* echo TVarDumper::dump($var);
* </code>
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @version $Id$
* @package System.Util
* @since 3.0
*/
class TVarDumper
{
private static $_objects;
private static $_output;
private static $_depth;
/**
* Converts a variable into a string representation.
* This method achieves the similar functionality as var_dump and print_r
* but is more robust when handling complex objects such as PRADO controls.
* @param mixed variable to be dumped
* @param integer maximum depth that the dumper should go into the variable. Defaults to 10.
* @return string the string representation of the variable
*/
public static function dump($var,$depth=10,$highlight=false)
{
self::$_output='';
self::$_objects=array();
self::$_depth=$depth;
self::dumpInternal($var,0);
if($highlight)
{
$result=highlight_string("<?php\n".self::$_output,true);
return preg_replace('/<\\?php<br \\/>/','',$result,1);
}
else
return self::$_output;
}
private static function dumpInternal($var,$level)
{
switch(gettype($var))
{
case 'boolean':
self::$_output.=$var?'true':'false';
break;
case 'integer':
self::$_output.="$var";
break;
case 'double':
self::$_output.="$var";
break;
case 'string':
self::$_output.="'$var'";
break;
case 'resource':
self::$_output.='{resource}';
break;
case 'NULL':
self::$_output.="null";
break;
case 'unknown type':
self::$_output.='{unknown}';
break;
case 'array':
if(self::$_depth<=$level)
self::$_output.='array(...)';
else if(empty($var))
self::$_output.='array()';
else
{
$keys=array_keys($var);
$spaces=str_repeat(' ',$level*4);
self::$_output.="array\n".$spaces.'(';
foreach($keys as $key)
{
self::$_output.="\n".$spaces." [$key] => ";
self::$_output.=self::dumpInternal($var[$key],$level+1);
}
self::$_output.="\n".$spaces.')';
}
break;
case 'object':
if(($id=array_search($var,self::$_objects,true))!==false)
self::$_output.=get_class($var).'#'.($id+1).'(...)';
else if(self::$_depth<=$level)
self::$_output.=get_class($var).'(...)';
else
{
$id=array_push(self::$_objects,$var);
$className=get_class($var);
$members=(array)$var;
$keys=array_keys($members);
$spaces=str_repeat(' ',$level*4);
self::$_output.="$className#$id\n".$spaces.'(';
foreach($keys as $key)
{
$keyDisplay=strtr(trim($key),array("\0"=>':'));
self::$_output.="\n".$spaces." [$keyDisplay] => ";
self::$_output.=self::dumpInternal($members[$key],$level+1);
}
self::$_output.="\n".$spaces.')';
}
break;
}
}
}
使用XDebug PHP扩展,它将检测并忽略循环引用,例如:
echo xdebug_var_dump($object);
print_r
+ array_slice
根据此post,您可以尝试:
print_r(array_slice($desiredArray, 0, 4));
使用以下函数作为Drupal的Features模块的一部分(features.export.inc
):
/**
* Export var function
*/
function features_var_export($var, $prefix = '', $init = TRUE, $count = 0) {
if ($count > 50) {
// Recursion depth reached.
return '...';
}
if (is_object($var)) {
$output = method_exists($var, 'export') ? $var->export() : features_var_export((array) $var, '', FALSE, $count+1);
}
else if (is_array($var)) {
if (empty($var)) {
$output = 'array()';
}
else {
$output = "array(\n";
foreach ($var as $key => $value) {
// Using normal var_export on the key to ensure correct quoting.
$output .= " " . var_export($key, TRUE) . " => " . features_var_export($value, ' ', FALSE, $count+1) . ",\n";
}
$output .= ')';
}
}
else if (is_bool($var)) {
$output = $var ? 'TRUE' : 'FALSE';
}
else if (is_int($var)) {
$output = intval($var);
}
else if (is_numeric($var)) {
$floatval = floatval($var);
if (is_string($var) && ((string) $floatval !== $var)) {
// Do not convert a string to a number if the string
// representation of that number is not identical to the
// original value.
$output = var_export($var, TRUE);
}
else {
$output = $floatval;
}
}
else if (is_string($var) && strpos($var, "\n") !== FALSE) {
// Replace line breaks in strings with a token for replacement
// at the very end. This protects whitespace in strings from
// unintentional indentation.
$var = str_replace("\n", "***BREAK***", $var);
$output = var_export($var, TRUE);
}
else {
$output = var_export($var, TRUE);
}
if ($prefix) {
$output = str_replace("\n", "\n$prefix", $output);
}
if ($init) {
$output = str_replace("***BREAK***", "\n", $output);
}
return $output;
}
用法:
echo features_var_export($object);
使用serialize
以序列化表示形式转储对象,例如:
echo serialize($object);
使用json_encode
将其转换为JSON格式,例如:
echo json_encode($object);
答案 3 :(得分:4)
<击>
您可以使用var_export()
。
<击>
var_export()不处理循环
引用因为它接近
不可能生成可解析的PHP
代码。如果你想做
具有完整代表性的东西
一个数组或对象,使用
连载()。
击>
更新:好像我错了。我以为我之前为此目的使用过这个功能,但它肯定是一些醉酒的想象力。
这样,我可以给出的唯一建议就是安装Xdebug。
答案 4 :(得分:2)
class Test {
public $obj;
}
$obj = new Test();
$obj->obj = $obj;
print_r($obj);
var_dump($obj);
输出:
Test Object
(
[obj] => Test Object
*RECURSION*
)
object(Test)[1]
public 'obj' =>
&object(Test)[1]
在我看来,print_r()
和var_dump()
都可以处理递归而没有任何问题。在Windows上使用PHP 5.3.5。
var_export()
未检测到递归,这会导致即时致命错误:
Fatal error: Nesting level too deep - recursive dependency? in \sandbox\index.php on line 28
答案 5 :(得分:1)
我也有这个问题,我通过实现__get()方法来破解参考圈来解决它。在类声明中找不到属性后调用__get()方法。 __get()方法还获取缺少属性的名称。使用它你可以定义“虚拟属性”,它们的工作方式与普通方法相同,但print_r函数没有提到。这是一个例子:
public function __get($name)
{
if ($name=="echo") {
return Zend_Registry::get('textConfig');
}
}
答案 6 :(得分:0)
这似乎让我完成了工作:
print_r(json_decode(json_encode($value)));
答案 7 :(得分:0)
Symfony现在还具有VarDumer组件: https://symfony.com/doc/current/components/var_dumper.html
它处理循环引用并支持远程转储服务器。
安装非常简单:
composer require symfony/var-dumper --dev
然后您可以使用全局函数dump
(我想已经包含了作曲家的autoload.php):
<?php
/* ... */
dump($someVar);