custom var_dump output for my class
Asked Answered
F

6

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.

Folketing answered 17/5, 2013 at 13:30 Comment(0)
E
17

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.
Expugnable answered 20/9, 2014 at 4:1 Comment(0)
P
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

Propellant answered 17/5, 2013 at 13:35 Comment(3)
thanks, but it doesn't affect output of var_dump. Is var_dump output hardwired, or can it be customized for a particular class?Folketing
You can't override php functions. You can build your own var_dump function and grab all the information you need.Transcendental
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.Folketing
N
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;
Nixie answered 17/5, 2013 at 13:35 Comment(1)
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.Folketing
C
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

Curdle answered 17/5, 2013 at 13:49 Comment(2)
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.Folketing
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 recommendedCurdle
C
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);
    }
}
Create answered 10/11, 2021 at 11:28 Comment(0)
P
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",
    ]),
  ],
];
Penetrating answered 29/8, 2023 at 15:25 Comment(1)
Welcome to Stack Overflow and thanks for your contribution, however the OP asked for a solution that will "customize behavior for var_dump in my library project" rather than use an external website on the output everytime to reformat it. If this answer can be adapted to answer the specific question asked, then you can edit your answer to add the relevant information.Hostelry

© 2022 - 2024 — McMap. All rights reserved.