11

is it possible to override var_dump output for a custom class? I want something like this:

class MyClass{
    public $foo;
    public $bar;
    //pseudo-code
    public function __dump($foo, $bar)
    {
        return 'Foo:$foo, bar:$bar';
    }
}

var_dump(array($instanceOfMyClass));
//it should output this:
array(1) {
  [0] =>
  class MyClass#1 (2) {
    Foo:valueOfFoo, bar:valueOfBar
  }
}

I know I can use some 3rd-party var_dump alternatives, but I want to customize behavior for var_dump in my library project.

Thanks.

amik
  • 5,613
  • 3
  • 37
  • 62

6 Answers6

16

In PHP 5.6.0+, you can use the __debugInfo() magic function to customize the output of var_dump().

array __debugInfo ( void )

This method is called by var_dump() when dumping an object to get the properties that should be shown. If the method isn't defined on an object, then all public, protected and private properties will be shown.

This feature was added in PHP 5.6.0.

Example:

class MyDateTime{
    public $year, $month, $day, $hour, $minute, $second;
    public function __debugInfo() {
        return array(
            'date' => $this->year . "-" . $this->month . "-" . $this->day,
            'time' => sprintf("%02d:%02d:%02d", $this->hour, $this->minute, $this->second),
        );
    }
}

$dt = new MyDateTime();
$dt->year = 2014; $dt->month = 9; $dt->day = 20;
$dt->hour = 16; $dt->minute = 2; $dt->second = 41;
var_dump($dt);

Output by PHP 5.6.0:

object(MyDateTime)#1 (2) {
  ["date"]=>
  string(9) "2014-9-20"
  ["time"]=>
  string(8) "16:02:41"
}

Output by PHP 5.0.0 - 5.5.16:

object(MyDateTime)#1 (6) {
  ["year"]=>
  int(2014)
  ["month"]=>
  int(9)
  ["day"]=>
  int(20)
  ["hour"]=>
  int(16)
  ["minute"]=>
  int(2)
  ["second"]=>
  int(41)
}

Notes:

  1. __debugInfo() must return an array. I got an error on PHP 5.6.0 for returning a string:

    Fatal error: __debuginfo() must return an array in /somepath/somefile.php on line 15

  2. It seems to work with print_r() too, although this doesn't seem documented anywhere.
Pang
  • 9,564
  • 146
  • 81
  • 122
1

For this you could use the ReflectionClass functions and build your own function to get the informations you need.

http://php.net/manual/de/reflectionclass.tostring.php
http://php.net/manual/en/book.reflection.php

René Höhle
  • 26,716
  • 22
  • 73
  • 82
  • thanks, but it doesn't affect output of var_dump. Is var_dump output hardwired, or can it be customized for a particular class? – amik May 17 '13 at 13:50
  • 1
    You can't override php functions. You can build your own var_dump function and grab all the information you need. – René Höhle May 17 '13 at 13:51
  • 1
    I don't want to override PHP function, I want to customize its behavior for a particular class. The question was if the behavior of var_dump for a particular class can be overriden i.e. by magic method. – amik May 17 '13 at 14:17
0

You cant overwrite core PHP functions.

You could add the function __toString() in your object:

class myClass {
    public function __toString(){
        // custom var_dump() content here then output it
    }
}

$myClass = new myClass();

echo $myClass;
Phil Cross
  • 9,017
  • 12
  • 50
  • 84
  • Thanks, but I know how to use __toString. I want to simplify the var_dump output when dumping complex structures of generic PHP classes, and some of my classes between them which can be dumped a more simple way. – amik May 17 '13 at 13:48
0

Don't make sense override var_dump result, you can just use toString() magic method

class MyClass{
public $foo;
public $bar;
public function test(){}
public function __toString()
 {
    $vars="Variables:";
    foreach(get_class_vars(__CLASS__) as $name => $value) $vars.="<br> $name : {$this->{$name}}".gettype($this->{$name});
    return __CLASS__.':<br>'.$vars.'<br>Methods:<br>'.implode('<br>',get_class_methods(__CLASS__));
 }
}

$lol = new MyClass();
$lol->foo = 10;
$lol->bar = 'asd';

 echo $lol;

Example HERE

Sam
  • 2,950
  • 1
  • 18
  • 26
  • know how to use toString. The point is, I have complex object structure (PHP arrays and other classes), part of the structure are my class objects that can be simplified. I want to dump whole this structure with var_dump, with customized output of the part of my class. – amik May 17 '13 at 14:16
  • you can't costumize the output because var_dump is a php function with direct output, the most you can do is filter the output with ob_ functions and edit that with some regular expressions but it's not recommended – Sam May 17 '13 at 14:22
0

If You're looking for a more readable (subjectively) var_dump, I've written something like that some time ago, maybe it'll be of use to You :)

I wanted to print_r every object as if it was an array. The quality of the code is not the best, but it helped me when I couldn't use XDebug.

class XDump
{
    private static array $object_hash = []; //workaround for cyclic dependencies

    public static function dump($var, bool $withContent = true, ?int $maxDepth = null): void
    {
        $dumpVar = self::convertToArray($var, $withContent, $maxDepth);
        print_r($dumpVar);
        exit();
    }

    private static function convertToArray($var, bool $withContent, ?int $maxDepth)
    {
        self::$object_hash = [];

        if (!$withContent) {
            return self::getArrayStructure($var, $maxDepth);
        }

        return self::getArray($var, $maxDepth);
    }

    private static function getArray($obj, ?int $maxDepth, $mainKey = '', int $depth = 0)
    {
        $simpleReturn = self::getSimpleReturn($obj, $mainKey);
        if (null !== $simpleReturn) {
            return $simpleReturn;
        }

        $result = [];
        $objectArray = (array)$obj;
        foreach ($objectArray as $key => $item) {
            if (!$maxDepth || $depth <= $maxDepth) {
                $result[$key] = self::getArray($item, $maxDepth, $key, $depth + 1);
            }
        }

        return self::shortenArray($result);
    }

    private static function getArrayStructure($obj, ?int $maxDepth, $mainKey = '', int $depth = 0)
    {
        $simpleReturn = self::getSimpleReturn($obj, $mainKey);
        if (null !== $simpleReturn) {
            return $simpleReturn;
        }

        $result = [];
        $objectArray = (array)$obj;
        foreach ($objectArray as $key => $item) {
            if (self::hasChildren($item)) {
                if (!$maxDepth || $depth <= $maxDepth) {
                    $result[$key] = self::getArrayStructure($item, $maxDepth, (string)$key, $depth + 1);
                }
            } else {
                self::throwErrorIfNotPrintable($key, $mainKey);
                $result['elements'][] = $key;
            }
        }
        if (isset($result['elements'])) {
            $elements = implode(' | ', $result['elements']);
            if (1 === \count($result)) {
                return $elements;
            }

            $result['elements'] = $elements;
        }

        return self::shortenArray($result);
    }

    private static function hasChildren($obj): bool
    {
        return \is_object($obj) || \is_array($obj);
    }

    private static function getHashIfAlreadyHashed($obj): ?string
    {
        $hash = self::getObjectHash($obj);
        $existingHash = self::$object_hash[$hash] ?? null;
        self::$object_hash[$hash] = $hash;

        return $existingHash;
    }

    private static function throwErrorIfNotPrintable($obj, string $name = 'object'): void
    {
        if (!self::isPrintable($obj)) {
            $type = \gettype($obj);
            throw new ServerException("Value of {$name} with type {$type} is not handled!");
        }
    }

    private static function isPrintable($obj): bool
    {
        return is_scalar($obj) || null === $obj;
    }

    private static function getSimpleReturn($obj, $mainKey)
    {
        if (\is_object($obj)) {
            if (is_subclass_of($obj, \DateTimeInterface::class)) {
                return TimeHelper::toDateTimeString($obj);
            }
            if (\Closure::class === \get_class($obj)) {
                return 'Closure';
            }

            $existingHash = self::getHashIfAlreadyHashed($obj);
            if (null !== $existingHash) {
                return "Already hashed somewhere else as {$existingHash}!";
            }
        }

        if (\is_string($obj)) {
            $jsonData = json_decode($obj, true);
            if ($jsonData) {
                $jsonData['XDump_IS_JSON_STRING'] = true;

                return $jsonData;
            }
        }

        if (\is_resource($obj)) {
            $type = get_resource_type($obj);

            return "PHP resource with type: {$type} in {$mainKey}";
        }

        if (!self::hasChildren($obj)) {
            self::throwErrorIfNotPrintable($obj);

            return $obj;
        }

        return null;
    }

    private static function shortenArray(array $retArray): array
    {
        $shortenRet = [];
        foreach ($retArray as $key => $item) {
            $shortKey = self::shortenKey((string)$key);
            $shortenRet[$shortKey] = $item;
        }

        return $shortenRet;
    }

    private static function shortenKey($key): string
    {
        try {
            $parts = explode("\0", $key);
            $shortKey = end($parts);
        } catch (\Throwable $e) {
            $shortKey = $key;
        }

        return $shortKey;
    }

    private static function getObjectHash($obj): string
    {
        return \get_class($obj).'|'.spl_object_hash($obj);
    }
}
Socratex
  • 1
  • 2
0

Whenever I have a var_dump output, I just paste it in https://www.spaggetticode.com/text-manipulation/php-dump so that I can view it as JSON or PHP array code instead. Maybe useful?

For example, my var_dump output was

array(1) {
  ["object"]=>
  object(stdClass)#4 (4) {
    ["create"]=>
    string(6) "sipper"
    ["faom"]=>
    array(2) {
      ["roam"]=>
      object(stdClass)#1 (3) {
        ["coam"]=>
        string(4) "zoam"
        ["bob"]=>
        string(3) "rob"
        ["fas"]=>
        int(124)
      }
      ["fas"]=>
      bool(false)
    }
    ["zom"]=>
    object(stdClass)#2 (1) {
      ["hello"]=>
      string(5) "world"
    }
    ["vom"]=>
    object(DateTime)#3 (3) {
      ["date"]=>
      string(26) "2023-08-29 14:52:23.647869"
      ["timezone_type"]=>
      int(3)
      ["timezone"]=>
      string(3) "UTC"
    }
  }
}

and the tool converts it to

return [
  "object" => (object)[
    "create" => "sipper",
    "faom" => [
      "roam" => (object)[
        "coam" => "zoam",
        "bob" => "rob",
        "fas" => 124,
      ],
      "fas" => false,
    ],
    "zom" => (object)[
      "hello" => "world",
    ],
    "vom" => new DateTime([
      "date" => "2023-08-29 14:52:23.647869",
      "timezone_type" => 3,
      "timezone" => "UTC",
    ]),
  ],
];
You
  • 1
  • 1