Debug::dumpAsHtml()   F
last analyzed

Complexity

Conditions 32
Paths 532

Size

Total Lines 153
Code Lines 72

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 1 Features 0
Metric Value
c 3
b 1
f 0
dl 0
loc 153
rs 2.6417
cc 32
eloc 72
nc 532
nop 0

How to fix   Long Method    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
 * @package    Fuel\Common
4
 * @version    2.0
5
 * @author     Fuel Development Team
6
 * @license    MIT License
7
 * @copyright  2010 - 2015 Fuel Development Team
8
 * @link       http://fuelphp.com
9
 */
10
11
namespace Fuel\Common;
12
13
/**
14
 * Debug class, helper class to assign in debugging the application
15
 *
16
 * @package Fuel\Common
17
 *
18
 * @since 2.0
19
 */
20
class Debug
21
{
22
	/**
23
	 * @var  int  Maximum nesting level for dump output
24
	 */
25
	protected $maxNestingLevel = 5;
26
27
	/**
28
	 * @var  bool  Whether or not the dump nesting is opened by default
29
	 */
30
	protected $jsOpenToggle = false;
31
32
	/**
33
	 * @var  bool  Flag to track if the required javascript has already been sent
34
	 */
35
	protected $jsDisplayed = false;
36
37
	/**
38
	 * @var  array  Cache for fileLines(), to avoid duplicate lookups
39
	 */
40
	protected $filesCache = array();
41
42
	/**
43
	 * @var  DataContainer  Input datacontainer
44
	 */
45
	protected $input;
46
47
	/**
48
	 * @var  Inflector  Inflector instance
49
	 */
50
	protected $inflector;
51
52
	/**
53
	 */
54
	public function __construct($input, $inflector)
55
	{
56
		$this->input = $input;
57
		$this->inflector = $inflector;
58
	}
59
60
	/**
61
	 * Setter for maxNestingLevel
62
	 *
63
	 * @param  int  Maximum nesting level for dump output
64
	 *
65
	 * @return  int  The current nesting level
66
	 */
67
	public function setNestingLevel($level = null)
68
	{
69
		if (func_num_args() and is_numeric($level) and $level > 0)
70
		{
71
			$this->maxNestingLevel = $level;
0 ignored issues
show
Documentation Bug introduced by WanWizard
It seems like $level can also be of type double or string. However, the property $maxNestingLevel is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

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

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
72
		}
73
74
		return $this->maxNestingLevel;
75
	}
76
77
	/**
78
	 * Setter for jsToggleOpen
79
	 *
80
	 * @param  bool  true for Open by default, false for closed
81
	 *
82
	 * @return  bool  The current toggle state
83
	 */
84
	public function setOpenToggle($toggle = null)
85
	{
86
		if (func_num_args() and is_bool($toggle))
87
		{
88
			$this->jsOpenToggle = $toggle;
89
		}
90
91
		return $this->jsOpenToggle;
92
	}
93
94
	/**
95
	 * Quick and nice way to output mixed variable(s)
96
	 */
97
	public function dump()
98
	{
99
		if ((bool) defined('STDIN'))
100
		{
101
			// no fancy flying on the commandline, just dump 'm
102
			foreach (func_get_args() as $arg)
103
			{
104
				var_dump($arg);
0 ignored issues
show
Security Debugging Code introduced by WanWizard
var_dump($arg); looks like debug code. Are you sure you do not want to remove it? This might expose sensitive data.
Loading history...
105
			}
106
		}
107
		else
108
		{
109
			// @codeCoverageIgnoreStart
110
			call_user_func_array(array($this, 'dumpAsHtml'), func_get_args());
111
			// @codeCoverageIgnoreEnd
112
		}
113
	}
114
115
	/**
116
	 * Quick and nice way to output mixed variable(s) to the browser
117
	 */
118
	public function dumpAsHtml()
119
	{
120
		$arguments = func_get_args();
121
		$total = count($arguments);
122
123
		$backtrace = debug_backtrace();
124
125
		// locate the first file entry that isn't this class itself
126
		foreach ($backtrace as $stack => $trace)
127
		{
128
			if (isset($trace['file']))
129
			{
130
				// If being called from within, or using call_user_func(), get the next entry
131
				if (strpos($trace['function'], 'call_user_func') === 0 or (isset($trace['class']) and $trace['class'] == get_class($this)))
132
				{
133
					continue;
134
				}
135
136
				$callee = $trace;
137
				$label = $this->inflector->humanize($backtrace[$stack+1]['function']);
0 ignored issues
show
Unused Code introduced by WanWizard
$label 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...
138
139
				// get info about what was dumped
140
				$callee['code'] = '';
141
				for ($i = $callee['line']; $i > 0; $i--)
142
				{
143
					$line = $this->fileLines($callee['file'], $i, false, 0);
144
					$callee['code'] = reset($line).' '.trim($callee['code']);
145
					$tokens = token_get_all('<?php '.trim($callee['code']));
146
					if (is_array($tokens[1]) and isset($tokens[1][0]) and $tokens[1][0] != 377)
147
					{
148
						break;
149
					}
150
				}
151
152
				$results = array();
153
				$r = false;
154
				$c = 0;
155
156
				foreach($tokens as $token)
0 ignored issues
show
Bug introduced by WanWizard
The variable $tokens does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
157
				{
158
					// skip everything before our function call
159
					if ($r === false)
160
					{
161
						if (isset($token[1]) and $token[1] == $callee['function'])
162
						{
163
							$r = 0;
164
						}
165
						continue;
166
					}
167
168
					// and quit if we find an end-of-statement
169
					if ($token == ';')
170
					{
171
						break;
172
					}
173
174
					// check for a start-of-expresssion
175
					elseif ($token == '(')
176
					{
177
						$c++;
178
						if ($c === 1)
179
						{
180
							continue;
181
						}
182
					}
183
184
					// check for an end-of-expresssion
185
					elseif ($token == ')')
186
					{
187
						$c--;
188
						if ($c === 0)
189
						{
190
							$r++;
191
							continue;
192
						}
193
					}
194
195
					// new expression in the same dump
196
					elseif ($token == ',' and $c === 1)
197
					{
198
						$r++;
199
						continue;
200
					}
201
202
					// make sure we have an array entry to add to, and add the token
203
					if ( ! isset($results[$r]))
204
					{
205
						$results[$r] = '';
206
					}
207
					$results[$r] .= is_array($token) ? $token[1] : $token;
208
				}
209
210
				// make sure we've parsed the same number of expressions as we have arguments
211
				if (count($results) == $total)
212
				{
213
					$callee['code'] = $results;
214
				}
215
				else
216
				{
217
					// parsing failed, try it the old fashioned way
218
					if (preg_match('/(.*'.$callee['function'].'\()(.*?)\);(.*)/', $callee['code'], $matches))
219
					{
220
						$callee['code'] = 'Variable'.($total==1?'':'s').' dumped: '.$matches[2];
221
					}
222
				}
223
224
				$callee['file'] = cleanpath($callee['file']);
225
226
				break;
227
			}
228
		}
229
230
		if ( ! $this->jsDisplayed)
231
		{
232
			echo <<<JS
233
<script type="text/javascript">function fuel_debug_toggle(a){if(document.getElementById){if(document.getElementById(a).style.display=="none"){document.getElementById(a).style.display="block"}else{document.getElementById(a).style.display="none"}}else{if(document.layers){if(document.id.display=="none"){document.id.display="block"}else{document.id.display="none"}}else{if(document.all.id.style.display=="none"){document.all.id.style.display="block"}else{document.all.id.style.display="none"}}}};</script>
234
JS;
235
			$this->jsDisplayed = true;
236
		}
237
238
		echo '<div class="fuelphp-dump" style="font-size: 13px;background: #EEE !important; border:1px solid #666; color: #000 !important; padding:10px;">';
239
		echo '<h1 style="padding: 0 0 5px 0; margin: 0; font: bold 110% sans-serif;">File: '.$callee['file'].' @ line: '.$callee['line'].'</h1>';
0 ignored issues
show
Bug introduced by WanWizard
The variable $callee does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
240
		if (is_string($callee['code']))
241
		{
242
			echo '<h5 style="border-bottom: 1px solid #CCC;padding: 0 0 5px 0; margin: 0 0 5px 0; font: bold 85% sans-serif;">'.$callee['code'].'</h5>'.PHP_EOL;
243
		}
244
		echo '<pre style="overflow:auto;font-size:100%;">';
245
246
		$i = 0;
247
		foreach ($arguments as $argument)
248
		{
249
			if (is_string($callee['code']))
250
			{
251
				echo '<strong>Variable #'.(++$i).' of '.$total.':</strong>'.PHP_EOL;
252
			}
253
			elseif (substr(trim($callee['code'][$i]),0,1) == '$')
254
			{
255
				echo '<strong>Variable: '.trim($callee['code'][$i++]).'</strong>'.PHP_EOL;
256
			}
257
			else
258
			{
259
				echo '<strong>Expression: '.trim($callee['code'][$i++]).'</strong>'.PHP_EOL;
260
			}
261
			echo $this->format('', $argument);
262
			if ($i < $total)
263
			{
264
				echo PHP_EOL;
265
			}
266
		}
267
268
		echo "</pre>";
269
		echo "</div>";
270
	}
271
272
	/**
273
	 * Formats the given $var's output in a nice looking, Foldable interface.
274
	 *
275
	 * @param	string	$name	the name of the var
276
	 * @param	mixed	$var	the variable
277
	 * @param	int		$level	the indentation level
278
	 * @param	string	$indent_char	the indentation character
279
	 * @return	string	the formatted string.
280
	 */
281
	public function format($name, $var, $level = 0, $indent_char = '&nbsp;&nbsp;&nbsp;&nbsp;', $scope = '')
282
	{
283
		static $itemCounter = 1;
284
285
		$return = str_repeat($indent_char, $level);
286
287
		if (is_array($var))
288
		{
289
			$id = 'fuel_debug_'.$itemCounter++;
290
			$return .= "<i>{$scope}</i> <strong>{$name}</strong>";
291
			$return .=  " (Array, ".count($var)." element".(count($var)!=1?"s":"").")";
292
			if (count($var) > 0 and $this->maxNestingLevel > $level)
293
			{
294
				$return .= " <a href=\"javascript:fuel_debug_toggle('$id');\" title=\"Click to ".(($this->jsOpenToggle or $level == 0)?"close":"open")."\">&crarr;</a>".PHP_EOL;
295
			}
296
			else
297
			{
298
				$return .= PHP_EOL;
299
			}
300
301
			if ($this->maxNestingLevel <= $level)
302
			{
303
				$return .= str_repeat($indent_char, $level + 1)."...".PHP_EOL;
304
			}
305
			else
306
			{
307
				$sub_return = '';
308
				foreach ($var as $key => $val)
309
				{
310
					$sub_return .= $this->format($key, $val, $level + 1);
311
				}
312 View Code Duplication
				if (count($var) > 0)
0 ignored issues
show
Duplication introduced by WanWizard
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...
313
				{
314
					$return .= "<span id=\"$id\" style=\"display: ".(($this->jsOpenToggle or $level == 0)?"block":"none").";\">$sub_return</span>";
315
				}
316
				else
317
				{
318
					$return .= $sub_return;
319
				}
320
			}
321
322
		}
323
		elseif (is_string($var))
324
		{
325
			$return .= "<i>{$scope}</i> <strong>{$name}</strong> (String): <span style=\"color:#E00000;\">\"".htmlentities($var, ENT_QUOTES, 'UTF-8', false)."\"</span> (".strlen($var)." characters)".PHP_EOL;
326
		}
327
		elseif (is_float($var))
328
		{
329
			$return .= "<i>{$scope}</i> <strong>{$name}</strong> (Float): {$var}".PHP_EOL;
330
		}
331
		elseif (is_int($var))
332
		{
333
			$return .= "<i>{$scope}</i> <strong>{$name}</strong> (Integer): {$var}".PHP_EOL;
334
		}
335
		elseif (is_null($var))
336
		{
337
			$return .= "<i>{$scope}</i> <strong>{$name}</strong> : null".PHP_EOL;
338
		}
339
		elseif (is_bool($var))
340
		{
341
			$return .= "<i>{$scope}</i> <strong>{$name}</strong> (Boolean): ".($var ? 'true' : 'false').PHP_EOL;
342
		}
343
		elseif (is_object($var))
344
		{
345
			// dirty hack to get the object id
346
			ob_start();
347
			var_dump($var);
0 ignored issues
show
Security Debugging Code introduced by WanWizard
var_dump($var); looks like debug code. Are you sure you do not want to remove it? This might expose sensitive data.
Loading history...
348
			$contents = ob_get_contents();
349
			ob_end_clean();
350
351
			// process it based on the xdebug presence and configuration
352
			// @codeCoverageIgnoreStart
353
			if (extension_loaded('xdebug') and ini_get('xdebug.overload_var_dump') === '1')
354
			{
355
				if (ini_get('html_errors'))
356
				{
357
					preg_match('~(.*?)\)\[<i>(\d+)(.*)~', $contents, $matches);
358
				}
359
				else
360
				{
361
					preg_match('~class (.*?)#(\d+)(.*)~', $contents, $matches);
362
				}
363
			}
364
			else
365
			{
366
				preg_match('~object\((.*?)#(\d+)(.*)~', $contents, $matches);
367
			}
368
			// @codeCoverageIgnoreEnd
369
370
			$id = 'fuel_debug_'.$itemCounter++;
371
			$rvar = new \ReflectionObject($var);
372
			$vars = $rvar->getProperties();
373
			$return .= "<i>{$scope}</i> <strong>{$name}</strong> (Object #".$matches[2]."): ".get_class($var);
374
			if (count($vars) > 0 and $this->maxNestingLevel > $level)
375
			{
376
				$return .= " <a href=\"javascript:fuel_debug_toggle('$id');\" title=\"Click to ".($this->jsOpenToggle?"close":"open")."\">&crarr;</a>".PHP_EOL;
377
			}
378
379
			$sub_return = '';
380
			foreach ($rvar->getProperties() as $prop)
381
			{
382
				$prop->isPublic() or $prop->setAccessible(true);
383
				if ($prop->isPrivate())
384
				{
385
					$scope = '<span style="color:red;">private</span>';
386
				}
387
				elseif ($prop->isProtected())
388
				{
389
					$scope = '<span style="color:blue;">protected</span>';
390
				}
391
				else
392
				{
393
					$scope = '<span style="color:green;">public</span>';
394
				}
395
				if ($this->maxNestingLevel <= $level)
396
				{
397
					$sub_return .= str_repeat($indent_char, $level + 1)."...".PHP_EOL;
398
				}
399
				else
400
				{
401
					$sub_return .= $this->format($prop->name, $prop->getValue($var), $level + 1, $indent_char, $scope);
402
				}
403
			}
404
405 View Code Duplication
			if (count($vars) > 0)
0 ignored issues
show
Duplication introduced by WanWizard
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...
406
			{
407
				$return .= "<span id=\"$id\" style=\"display: ".($this->jsOpenToggle?"block":"none").";\">$sub_return</span>";
408
			}
409
			else
410
			{
411
				$return .= $sub_return;
412
			}
413
		}
414
		else
415
		{
416
			$return .= "<i>{$scope}</i> <strong>{$name}</strong>: {$var}".PHP_EOL;
417
		}
418
		return $return;
419
	}
420
421
	/**
422
	 * Returns the debug lines from the specified file
423
	 *
424
	 * @access	protected
425
	 * @param	string		the file path
426
	 * @param	int			the line number
427
	 * @param	bool		whether to use syntax highlighting or not
428
	 * @param	int			the amount of line padding
429
	 * @return	array
430
	 */
431
	public function fileLines($filepath, $line_num, $highlight = true, $padding = 5)
432
	{
433
		// deal with eval'd code
434
		if (strpos($filepath, 'eval()\'d code') !== false)
435
		{
436
			return '';
437
		}
438
439
		// We cache the entire file to reduce disk IO for multiple errors
440
		if ( ! isset($this->filesCache[$filepath]))
441
		{
442
			$this->filesCache[$filepath] = file($filepath, FILE_IGNORE_NEW_LINES);
443
			array_unshift($this->filesCache[$filepath], '');
444
		}
445
446
		$start = max(0, $line_num - $padding);
447
		$length = ($line_num - $start) + $padding + 1;
448
449
		if (($start + $length) > count($this->filesCache[$filepath]) - 1)
450
		{
451
			$length = null;
452
		}
453
454
		$debug_lines = array_slice($this->filesCache[$filepath], $start, $length, true);
455
456
		if ($highlight)
457
		{
458
			$to_replace = array('<code>', '</code>', '<span style="color: #0000BB">&lt;?php&nbsp;', PHP_EOL);
459
			$replace_with = array('', '', '<span style="color: #0000BB">', '');
460
461
			foreach ($debug_lines as &$line)
462
			{
463
				$line = str_replace($to_replace, $replace_with, highlight_string('<?php ' . $line, true));
464
			}
465
		}
466
467
		return $debug_lines;
468
	}
469
470
	public function backtrace()
471
	{
472
		return $this->dump(debug_backtrace());
473
	}
474
475
	/**
476
	* Prints a list of all currently declared classes.
477
	*
478
	* @access public
479
	*/
480
	public function classes()
481
	{
482
		return $this->dump(get_declared_classes());
483
	}
484
485
	/**
486
	* Prints a list of all currently declared interfaces (PHP5 only).
487
	*
488
	* @access public
489
	*/
490
	public function interfaces()
491
	{
492
		return $this->dump(get_declared_interfaces());
493
	}
494
495
	/**
496
	* Prints a list of all currently included (or required) files.
497
	*
498
	* @access public
499
	*/
500
	public function includes()
501
	{
502
	return $this->dump(get_included_files());
503
	}
504
505
	/**
506
	 * Prints a list of all currently declared functions.
507
	 *
508
	 * @access public
509
	 */
510
	public function functions()
511
	{
512
		return $this->dump(get_defined_functions());
513
	}
514
515
	/**
516
	 * Prints a list of all currently declared constants.
517
	 *
518
	 * @access public
519
	 */
520
	public function constants()
521
	{
522
		return $this->dump(get_defined_constants());
523
	}
524
525
	/**
526
	 * Prints a list of all currently loaded PHP extensions.
527
	 *
528
	 * @access public
529
	 */
530
	public function extensions()
531
	{
532
		return $this->dump(get_loaded_extensions());
533
	}
534
535
	/**
536
	 * Prints a list of all HTTP request headers.
537
	 *
538
	 * @access public
539
	 */
540
	public function headers()
541
	{
542
		// get the current request headers and dump them
543
		return $this->dump($this->input->headers());
0 ignored issues
show
Bug introduced by WanWizard
The method headers() does not seem to exist on object<Fuel\Common\DataContainer>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
544
	}
545
546
	/**
547
	 * Prints a list of the configuration settings read from <i>php.ini</i>
548
	 *
549
	 * @access public
550
	 */
551
	public function phpini()
552
	{
553
		return is_readable(get_cfg_var('cfg_file_path')) ? $this->dump(parse_ini_file(get_cfg_var('cfg_file_path'), true)) : false;
554
	}
555
556
	/**
557
	 * Benchmark anything that is callable
558
	 *
559
	 * @access public
560
	 */
561
	public function benchmark($callable, array $params = array())
562
	{
563
		// get the before-benchmark time
564
		list($usec, $sec) = explode(" ", microtime());
565
		$time_before = ((float)$usec + (float)$sec);
566
567
		// call the function to be benchmarked
568
		$result = is_callable($callable) ? call_user_func_array($callable, $params) : null;
569
570
		// get the after-benchmark time
571
		list($usec, $sec) = explode(" ", microtime());
572
		$time_after = ((float)$usec + (float)$sec);
573
574
		return array(
575
			'time' => sprintf('%1.6f', $time_after - $time_before),
576
			'result' => $result
577
		);
578
	}
579
580
}
581