gpt4 book ai didi

php - 如何在没有内存错误的情况下使用 var_dump + 输出缓冲?

转载 作者:IT王子 更新时间:2023-10-28 23:28:40 26 4
gpt4 key购买 nike

我在一个应用程序中使用调试辅助工具,该应用程序使用 var_dump() 和输出缓冲来捕获变量并显示它们。但是,我遇到了一个问题,即大型对象最终会占用缓冲区中的太多内存。

function getFormattedOutput(mixed $var) {
if (isTooLarge($var)) {
return 'Too large! Abort!'; // What a solution *might* look like
}

ob_start();
var_dump($var); // Fatal error: Allowed memory size of 536870912 bytes exhausted
$data = ob_get_clean();

// Return the nicely-formated data to use later
return $data
}

有什么办法可以防止这种情况发生吗?还是一种变通方法来检测它即将为特定变量输出大量信息?我真的无法控制哪些变量被传递到这个函数中。它可以是任何类型。

最佳答案

正如所有其他人都提到你所问的是不可能的。你唯一能做的就是尽量处理好它。

您可以尝试将其拆分为更小的部分,然后将其组合起来。我创建了一个小测试来尝试获取内存错误。显然,现实世界的示例可能表现不同,但这似乎可以解决问题。

<?php
define('mem_limit', return_bytes(ini_get('memory_limit'))); //allowed memory

/*
SIMPLE TEST CLASS
*/
class test { }
$loop = 260;
$t = new Test();
for ($x=0;$x<=$loop;$x++) {
$v = 'test'.$x;
$t->$v = new Test();
for ($y=0;$y<=$loop;$y++) {
$v2 = 'test'.$y;
$t->$v->$v2 = str_repeat('something to test! ', 200);
}
}
/* ---------------- */


echo saferVarDumpObject($t);

function varDumpToString($v) {
ob_start();
var_dump($v);
$content = ob_get_contents();
ob_end_clean();
return $content;
}

function saferVarDumpObject($var) {
if (!is_object($var) && !is_array($var))
return varDumpToString($var);

$content = '';
foreach($var as $v) {
$content .= saferVarDumpObject($v);
}
//adding these smaller pieces to a single var works fine.
//returning the complete larger piece gives memory error

$length = strlen($content);
$left = mem_limit-memory_get_usage(true);

if ($left>$length)
return $content; //enough memory left

echo "WARNING! NOT ENOUGH MEMORY<hr>";
if ($left>100) {
return substr($content, 0, $left-100); //100 is a margin I choose, return everything you have that fits in the memory
} else {
return ""; //return nothing.
}
}

function return_bytes($val) {
$val = trim($val);
$last = strtolower($val[strlen($val)-1]);
switch($last) {
// The 'G' modifier is available since PHP 5.1.0
case 'g':
$val *= 1024;
case 'm':
$val *= 1024;
case 'k':
$val *= 1024;
}

return $val;
}
?>

更新上面的版本仍然有一些错误。我重新创建它以使用一个类和一些其他功能

  • 检查递归
  • 修复单个大属性
  • 模拟 var_dump 输出
  • trigger_error on warning 以便能够捕获/隐藏它

如注释所示,类的资源标识符与 var_dump 的输出不同。据我所知,其他的都是一样的。

<?php  
/*
RECURSION TEST
*/
class sibling {
public $brother;
public $sister;
}
$brother = new sibling();
$sister = new sibling();
$brother->sister = $sister;
$sister->sister = $brother;
Dump::Safer($brother);


//simple class
class test { }

/*
LARGE TEST CLASS - Many items
*/
$loop = 260;
$t = new Test();
for ($x=0;$x<=$loop;$x++) {
$v = 'test'.$x;
$t->$v = new Test();
for ($y=0;$y<=$loop;$y++) {
$v2 = 'test'.$y;
$t->$v->$v2 = str_repeat('something to test! ', 200);
}
}
//Dump::Safer($t);
/* ---------------- */


/*
LARGE TEST CLASS - Large attribute
*/
$a = new Test();
$a->t2 = new Test();
$a->t2->testlargeattribute = str_repeat('1', 268435456 - memory_get_usage(true) - 1000000);
$a->smallattr1 = 'test small1';
$a->smallattr2 = 'test small2';
//Dump::Safer($a);
/* ---------------- */

class Dump
{
private static $recursionhash;
private static $memorylimit;
private static $spacing;
private static $mimicoutput = true;


final public static function MimicOutput($v) {
//show results similar to var_dump or without array/object information
//defaults to similar as var_dump and cancels this on out of memory warning
self::$mimicoutput = $v===false ? false : true;
}

final public static function Safer($var) {
//set defaults
self::$recursionhash = array();
self::$memorylimit = self::return_bytes(ini_get('memory_limit'));

self::$spacing = 0;

//echo output
echo self::saferVarDumpObject($var);
}

final private static function saferVarDumpObject($var) {
if (!is_object($var) && !is_array($var))
return self::Spacing().self::varDumpToString($var);

//recursion check
$hash = spl_object_hash($var);
if (!empty(self::$recursionhash[$hash])) {
return self::Spacing().'*RECURSION*'.self::Eol();
}
self::$recursionhash[$hash] = true;


//create a similar output as var dump to identify the instance
$content = self::Spacing() . self::Header($var);
//add some spacing to mimic vardump output
//Perhaps not the best idea because the idea is to use as little memory as possible.
self::$spacing++;
//Loop trough everything to output the result
foreach($var as $k=>$v) {
$content .= self::Spacing().self::Key($k).self::Eol().self::saferVarDumpObject($v);
}
self::$spacing--;
//decrease spacing and end the object/array
$content .= self::Spacing().self::Footer().self::Eol();
//adding these smaller pieces to a single var works fine.
//returning the complete larger piece gives memory error

//length of string and the remaining memory
$length = strlen($content);
$left = self::$memorylimit-memory_get_usage(true);

//enough memory left?
if ($left>$length)
return $content;

//show warning
trigger_error('Not enough memory to dump "'.get_class($var).'" memory left:'.$left, E_USER_WARNING);
//stop mimic output to prevent fatal memory error
self::MimicOutput(false);
if ($left>100) {
return substr($content, 0, $left-100); //100 is a margin I chose, return everything you have that fits in the memory
} else {
return ""; //return nothing.
}
}

final private static function Spacing() {
return self::$mimicoutput ? str_repeat(' ', self::$spacing*2) : '';
}

final private static function Eol() {
return self::$mimicoutput ? PHP_EOL : '';
}

final private static function Header($var) {
//the resource identifier for an object is WRONG! Its always 1 because you are passing around parts and not the actual object. Havent foundnd a fix yet
return self::$mimicoutput ? (is_array($var) ? 'array('.count($var).')' : 'object('.get_class($var).')#'.intval($var).' ('.count((array)$var).')') . ' {'.PHP_EOL : '';
}

final private static function Footer() {
return self::$mimicoutput ? '}' : '';
}

final private static function Key($k) {
return self::$mimicoutput ? '['.(gettype($k)=='string' ? '"'.$k.'"' : $k ).']=>' : '';
}

final private static function varDumpToString($v) {
ob_start();
var_dump($v);

$length = strlen($v);
$left = self::$memorylimit-memory_get_usage(true);

//enough memory left with some margin?
if ($left-100>$length) {
$content = ob_get_contents();
ob_end_clean();
return $content;
}
ob_end_clean();

//show warning
trigger_error('Not enough memory to dump "'.gettype($v).'" memory left:'.$left, E_USER_WARNING);

if ($left>100) {
$header = gettype($v).'('.strlen($v).')';
return $header . substr($v, $left - strlen($header));
} else {
return ""; //return nothing.
}
}

final private static function return_bytes($val) {
$val = trim($val);
$last = strtolower($val[strlen($val)-1]);
switch($last) {
// The 'G' modifier is available since PHP 5.1.0
case 'g':
$val *= 1024;
case 'm':
$val *= 1024;
case 'k':
$val *= 1024;
}

return $val;
}
}
?>

关于php - 如何在没有内存错误的情况下使用 var_dump + 输出缓冲?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5446647/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com