public static function dump($data, $level = 5)
    {
        static $innerLevel = 1;

        static $tabLevel = 1;

        $self = __FUNCTION__;

        $type = gettype($data);
        $tabs = str_repeat('    ', $tabLevel);
        $quoteTabes = str_repeat('    ', $tabLevel - 1);
        $output = '';
        $elements = [];

        $recursiveType = ['object', 'array'];

        // Recursive
        if (in_array($type, $recursiveType, true)) {
            // If type is object, try to get properties by Reflection.
            if ($type === 'object') {
                $output = get_class($data) . ' ' . ucfirst($type);
                $ref = new \ReflectionObject($data);
                $properties = $ref->getProperties();

                foreach ($properties as $property) {
                    $property->setAccessible(true);

                    $pType = $property->getName();

                    if ($property->isProtected()) {
                        $pType .= ':protected';
                    } elseif ($property->isPrivate()) {
                        $pType .= ':' . $property->class . ':private';
                    }

                    if ($property->isStatic()) {
                        $pType .= ':static';
                    }

                    $elements[$pType] = $property->getValue($data);
                }
            } elseif ($type === 'array') {
                // If type is array, just retun it's value.
                $output = ucfirst($type);
                $elements = $data;
            }

            // Start dumping data
            if ($level == 0 || $innerLevel < $level) {
                // Start recursive print
                $output .= "\n{$quoteTabes}(";

                foreach ($elements as $key => $element) {
                    $output .= "\n{$tabs}[{$key}] => ";

                    // Increment level
                    $tabLevel += 2;
                    $innerLevel++;

                    $output .= in_array(gettype($element), $recursiveType, true)
                        ? static::$self($element, $level)
                        : $element;

                    // Decrement level
                    $tabLevel -= 2;
                    $innerLevel--;
                }

                $output .= "\n{$quoteTabes})\n";
            } else {
                $output .= "\n{$quoteTabes}*MAX LEVEL*\n";
            }
        } else {
            $output = $data;
        }

        return $output;
    }