ExceptionUtils::getPhpVariableAsText()   D
last analyzed

Complexity

Conditions 10
Paths 9

Size

Total Lines 30
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 30
c 0
b 0
f 0
rs 4.8196
cc 10
eloc 23
nc 9
nop 1

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Mouf\Mvc\Splash\Utils;
4
5
class ExceptionUtils
6
{
7
    /**
8
     * Returns the Exception Backtrace as a nice HTML view.
9
     *
10
     * @param unknown_type $backtrace
11
     *
12
     * @return unknown
13
     */
14
    private static function getHTMLBackTrace($backtrace)
15
    {
16
        $str = '';
17
18
        foreach ($backtrace as $step) {
19
            if ($step['function'] != 'getHTMLBackTrace' && $step['function'] != 'handle_error') {
20
                $str .= '<tr><td style="border-bottom: 1px solid #EEEEEE">';
21
                $str .= ((isset($step['class'])) ? htmlspecialchars($step['class'], ENT_NOQUOTES, 'UTF-8') : '').
22
                ((isset($step['type'])) ? htmlspecialchars($step['type'], ENT_NOQUOTES, 'UTF-8') : '').htmlspecialchars($step['function'], ENT_NOQUOTES, 'UTF-8').'(';
23
24 View Code Duplication
                if (is_array($step['args'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
25
                    $drawn = false;
26
                    $params = '';
27
                    foreach ($step['args'] as $param) {
28
                        $params .= self::getPhpVariableAsText($param);
29
                        //$params .= var_export($param, true);
30
                        $params .= ', ';
31
                        $drawn = true;
32
                    }
33
                    $str .= htmlspecialchars($params, ENT_NOQUOTES, 'UTF-8');
34
                    if ($drawn == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
35
                        $str = substr($str, 0, strlen($str) - 2);
36
                    }
37
                }
38
                $str .= ')';
39
                $str .= '</td><td style="border-bottom: 1px solid #EEEEEE">';
40
                $str .= ((isset($step['file'])) ? htmlspecialchars(self::displayFile($step['file']), ENT_NOQUOTES, 'UTF-8') : '');
41
                $str .= '</td><td style="border-bottom: 1px solid #EEEEEE">';
42
                $str .= ((isset($step['line'])) ? $step['line'] : '');
43
                $str .= '</td></tr>';
44
            }
45
        }
46
47
        return $str;
48
    }
49
50
    /**
51
     * Function called to display an exception if it occurs.
52
     * It will make sure to purge anything in the buffer before calling the exception displayer.
53
     *
54
     * @param Exception $exception
55
     */
56
    public static function getHtmlForException(\Exception $exception)
57
    {
58
        //global $sys_error_reporting_mail;
59
        //global $sys_error_messages;
60
        $msg = '';
0 ignored issues
show
Unused Code introduced by
$msg is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
61
62
        $msg = '<table>';
63
64
        $display_errors = ini_get('display_errors');
0 ignored issues
show
Unused Code introduced by
$display_errors is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
65
        $color = '#FF0000';
66
        $type = 'Uncaught '.get_class($exception);
67
        if ($exception->getCode() != null) {
68
            $type .= ' with error code '.$exception->getCode();
69
        }
70
71
        $msg .= "<tr><td colspan='3' style='background-color:$color; color:white; text-align:center'><b>$type</b></td></tr>";
72
73
        $msg .= "<tr><td style='background-color:#AAAAAA; color:white; text-align:center'>Context/Message</td>";
74
        $msg .= "<td style='background-color:#AAAAAA; color:white; text-align:center'>File</td>";
75
        $msg .= "<td style='background-color:#AAAAAA; color:white; text-align:center'>Line</td></tr>";
76
77
        $msg .= "<tr><td style='background-color:#EEEEEE; color:black'><b>".nl2br($exception->getMessage()).'</b></td>';
78
        $msg .= "<td style='background-color:#EEEEEE; color:black'>".self::displayFile($exception->getFile()).'</td>';
79
        $msg .= "<td style='background-color:#EEEEEE; color:black'>".$exception->getLine().'</td></tr>';
80
        $msg .= self::getHTMLBackTrace($exception->getTrace());
0 ignored issues
show
Documentation introduced by
$exception->getTrace() is of type array, but the function expects a object<Mouf\Mvc\Splash\Utils\unknown_type>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
81
        $msg .= '</table>';
82
83
        return $msg;
84
    }
85
86
    /**
87
     * Function called to display an exception if it occurs.
88
     * It will make sure to purge anything in the buffer before calling the exception displayer.
89
     *
90
     * @param Exception $exception
91
     */
92
    public static function getTextForException(\Exception $exception)
93
    {
94
        // Now, let's compute the same message, but without the HTML markup for the error log.
95
        $textTrace = 'Message: '.$exception->getMessage()."\n";
96
        $textTrace .= 'File: '.$exception->getFile()."\n";
97
        $textTrace .= 'Line: '.$exception->getLine()."\n";
98
        $textTrace .= "Stacktrace:\n";
99
        $textTrace .= self::getTextBackTrace($exception->getTrace());
0 ignored issues
show
Documentation introduced by
$exception->getTrace() is of type array, but the function expects a object<Mouf\Mvc\Splash\Utils\unknown_type>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
100
101
        return $textTrace;
102
    }
103
    /**
104
     * Returns the Exception Backtrace as a text string.
105
     *
106
     * @param unknown_type $backtrace
107
     *
108
     * @return unknown
109
     */
110
    private static function getTextBackTrace($backtrace)
111
    {
112
        $str = '';
113
114
        foreach ($backtrace as $step) {
115
            if ($step['function'] != 'getTextBackTrace' && $step['function'] != 'handle_error') {
116
                if (isset($step['file']) && isset($step['line'])) {
117
                    $str .= 'In '.$step['file'].' at line '.$step['line'].': ';
118
                }
119
                if (isset($step['class']) && isset($step['type']) && isset($step['function'])) {
120
                    $str .= $step['class'].$step['type'].$step['function'].'(';
121
                }
122
123 View Code Duplication
                if (is_array($step['args'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
124
                    $drawn = false;
125
                    $params = '';
126
                    foreach ($step['args'] as $param) {
127
                        $params .= self::getPhpVariableAsText($param);
128
                        //$params .= var_export($param, true);
129
                        $params .= ', ';
130
                        $drawn = true;
131
                    }
132
                    $str .= $params;
133
                    if ($drawn == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
134
                        $str = substr($str, 0, strlen($str) - 2);
135
                    }
136
                }
137
                $str .= ')';
138
                $str .= "\n";
139
            }
140
        }
141
142
        return $str;
143
    }
144
145
    /**
146
     * Used by the debug function to display a nice view of the parameters.
147
     *
148
     * @param unknown_type $var
149
     *
150
     * @return unknown
151
     */
152
    private static function getPhpVariableAsText($var)
153
    {
154
        if (is_string($var)) {
155
            return('"'.str_replace(array("\x00", "\x0a", "\x0d", "\x1a", "\x09"), array('\0', '\n', '\r', '\Z', '\t'), $var).'"');
156
        } elseif (is_int($var) || is_float($var)) {
157
            return($var);
158
        } elseif (is_bool($var)) {
159
            if ($var) {
160
                return('true');
161
            } else {
162
                return('false');
163
            }
164
        } elseif (is_array($var)) {
165
            $result = 'array( ';
166
            $comma = '';
167
            foreach ($var as $key => $val) {
168
                $result .= $comma.self::getPhpVariableAsText($key).' => '.self::getPhpVariableAsText($val);
0 ignored issues
show
Documentation introduced by
$key is of type integer|string, but the function expects a object<Mouf\Mvc\Splash\Utils\unknown_type>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
169
                $comma = ', ';
170
            }
171
            $result .= ' )';
172
173
            return($result);
174
        } elseif (is_object($var)) {
175
            return 'Object '.get_class($var);
176
        } elseif (is_resource($var)) {
177
            return 'Resource '.get_resource_type($var);
178
        }
179
180
        return 'Unknown type variable';
181
    }
182
183
    private static function displayFile($file)
184
    {
185
        $realpath = realpath($file);
186
        if (!$realpath) {
187
            // If the file is a phar::// or something...
188
189
            return $file;
190
        }
191
        $cwd = getcwd().DIRECTORY_SEPARATOR;
192
193
        return self::getRelativePath($cwd, $realpath);
194
    }
195
196
    /**
197
     * Returns a relative path based on 2 absolute paths.
198
     *
199
     * @param string $from
200
     * @param string $to
201
     *
202
     * @return string
203
     */
204
    private static function getRelativePath($from, $to)
205
    {
206
        $from = explode('/', $from);
207
        $to = explode('/', $to);
208
        $relPath = $to;
209
210
        foreach ($from as $depth => $dir) {
211
            // find first non-matching dir
212
            if (isset($to[$depth]) && $dir === $to[$depth]) {
213
                // ignore this directory
214
                array_shift($relPath);
215
            } else {
216
                // get number of remaining dirs to $from
217
                $remaining = count($from) - $depth;
218
                if ($remaining > 1) {
219
                    // add traversals up to first matching dir
220
                    $padLength = (count($relPath) + $remaining - 1) * -1;
221
                    $relPath = array_pad($relPath, $padLength, '..');
222
                    break;
223
                } else {
224
                    $relPath[0] = './'.$relPath[0];
225
                }
226
            }
227
        }
228
229
        return implode('/', $relPath);
230
    }
231
}
232