amik
amik

Reputation: 5909

custom var_dump output for my class

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.

Upvotes: 11

Views: 12082

Answers (6)

You
You

Reputation: 1

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",
    ]),
  ],
];

Upvotes: 0

Socratex
Socratex

Reputation: 1

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);
    }
}

Upvotes: 0

Pang
Pang

Reputation: 10110

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.

Upvotes: 17

Sam
Sam

Reputation: 2970

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

Upvotes: 0

Phil Cross
Phil Cross

Reputation: 9302

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;

Upvotes: 0

Ren&#233; H&#246;hle
Ren&#233; H&#246;hle

Reputation: 27295

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

Upvotes: 1

Related Questions