Completed
Push — 1.x ( ce34cb...ebc2f4 )
by Akihito
02:21
created

ExceptionAsString::getTrace()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 0
cts 0
cp 0
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 6
nc 1
nop 1
crap 6
1
<?php
2
/**
3
 * This file is part of the BEAR.Package package.
4
 *
5
 * @license http://opensource.org/licenses/MIT MIT
6
 */
7
namespace BEAR\Package\Provide\Error;
8
9
use BEAR\Sunday\Extension\Router\RouterMatch as Request;
10
11
final class ExceptionAsString
12
{
13 3
    /**
14
     * @param \Exception $e
15 3
     * @param Request    $request
16
     *
17
     * @return string
18
     */
19
    public function __invoke(\Exception $e, Request $request)
0 ignored issues
show
Coding Style introduced by
__invoke uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
__invoke uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
20
    {
21
        $date = date(DATE_RFC2822);
22
        $exceptions = $this->getExceptionString($e);
23
        $context = isset($GLOBALS['context']) ? "({$GLOBALS['context']})" . PHP_EOL : '';
24 3
        $phpVal = $this->getPhpVariables();
25
        $trace = $this->getTrace($e);
26 3
27 3
        return <<<EOT
28 3
{$date}
29 3
{$request} {$context}
30 3
31 3
Exceptions:
32 3
33
{$exceptions}
34
Trace:
35 3
36
{$trace}
37
38
PHP Variables:
39
40
{$phpVal}
41
42
EOT;
43 3
44
        return sprintf("%s\n%s\n\n%s\nPHP Variables\n\n%sTrace:\n\n%s\n", date(DATE_RFC2822), $request, $eString, $this->getPhpVariables($_SERVER), $trace);
0 ignored issues
show
Unused Code introduced by
return sprintf('%s %s %...les($_SERVER), $trace); does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
45 3
    }
46 3
47
    private function getExceptionString(\Exception $e, $string = '')
48
    {
49
        $string .= sprintf(
50
            "%s(%s) in %s(%s)\n",
51
            get_class($e),
52
            $e->getMessage(),
53
            $e->getFile(),
54
            $e->getLine()
55
        );
56
        $previous = $e->getPrevious();
57
        if ($previous instanceof \Exception) {
58
            $string = $this->getExceptionString($previous, $string);
59
        }
60
61
        return $string;
62
    }
63
64
    /**
65
     * @return string
66
     */
67
    private function getPhpVariables()
0 ignored issues
show
Coding Style introduced by
getPhpVariables uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
getPhpVariables uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
getPhpVariables uses the super-global variable $_COOKIE which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
getPhpVariables uses the super-global variable $_FILES which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
getPhpVariables uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
68
    {
69
        $phpGlobals = [
70
            'GET' => $_GET,
71
            'POST' => $_POST,
72
            'COOKIE' => $_COOKIE,
73
            'FILES' => $_FILES,
74
            'SERVER' => $_SERVER
75
        ];
76
77
        return print_r($phpGlobals, true);
78
    }
79
80
    private function getTrace(\Exception $e)
81
    {
82
        $trace = $e->getTrace();
83
        $i = 0;
84
        array_walk($trace, function (&$trace, $index) use ($i) {
85
            $trace = isset($trace['class']) ? $this->getClassTrace($trace, $index) : $this->getFunctionTrace($trace, $index);
86
        });
87
88
        return implode(PHP_EOL, $trace);
89
    }
90
91
    private function getClassTrace(array $trace, $index)
92
    {
93
        $string = sprintf('#%d %s%s%s(%s)', $index, $trace['class'], $trace['type'], $trace['function'], $this->argsAsString($trace['args']));
94
95
        return isset($trace['file']) ? $string . sprintf(' in %s(%s)', $trace['file'], $trace['line']) : $string;
96
    }
97
98
    private function getFunctionTrace(array $trace, $index)
99
    {
100
        return sprintf('#%d %s(%s) in %s(%s)', $index, $trace['function'], $this->argsAsString($trace['args']), $trace['file'], $trace['line']);
101
    }
102
103
    private function argsAsString(array $args)
104
    {
105
        foreach ($args as &$arg) {
106
            if (is_object($arg)) {
107
                $arg = $this->objectAsString($arg);
108
                continue;
109
            }
110
            if (is_array($arg)) {
111
                $arg = $this->argsAsString($arg);
112
                continue;
113
            }
114
            if (is_string($arg)) {
115
                $arg = sprintf("'%s'", $arg);
116
            }
117
        }
118
119
        return implode(',', $args);
120
    }
121
122
    private function objectAsString($object)
123
    {
124
        return sprintf('Object(%s)', get_class($object));
125
    }
126
}
127