Test Setup Failed
Pull Request — master (#216)
by Viruthagiri
05:38
created

WPProfiler::array_sub()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 7
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 7
rs 9.4285
cc 3
eloc 6
nc 3
nop 2
1
<?php
2
3
/*
4
A simple manually-instrumented profiler for WordPress.
5
6
This records basic execution time, and a summary of the actions and SQL queries run within each block.
7
8
start() and stop() must be called in pairs, for example:
9
10
function something_to_profile() {
11
	wppf_start(__FUNCTION__);
12
	do_stuff();
13
	wppf_stop();
14
}
15
16
Multiple profile blocks are permitted, and they may be nested.
17
18
*/
19
20
class WPProfiler {
21
	var $stack;
22
	var $profile;
23
24
	/**
25
	 * PHP5 constructor.
26
	 */
27
	function __construct() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
28
		$this->stack = array();
29
		$this->profile = array();
30
	}
31
32
	function start($name) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
33
		$time = $this->microtime();
34
35
		if (!$this->stack) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->stack of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
36
			// log all actions and filters
37
			add_filter('all', array($this, 'log_filter'));
38
		}
39
40
		// reset the wpdb queries log, storing it on the profile stack if necessary
41
		global $wpdb;
42
		if ($this->stack) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->stack of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
43
			$this->stack[count($this->stack)-1]['queries'] = $wpdb->queries;
44
		}
45
		$wpdb->queries = array();
46
47
		global $wp_object_cache;
48
49
		$this->stack[] = array(
50
			'start' => $time,
51
			'name' => $name,
52
			'cache_cold_hits' => $wp_object_cache->cold_cache_hits,
53
			'cache_warm_hits' => $wp_object_cache->warm_cache_hits,
54
			'cache_misses' => $wp_object_cache->cache_misses,
55
			'cache_dirty_objects' => $this->_dirty_objects_count($wp_object_cache->dirty_objects),
56
			'actions' => array(),
57
			'filters' => array(),
58
			'queries' => array(),
59
		);
60
61
	}
62
63
	function stop() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
64
		$item = array_pop($this->stack);
65
		$time = $this->microtime($item['start']);
66
		$name = $item['name'];
67
68
		global $wpdb;
69
		$item['queries'] = $wpdb->queries;
70
		global $wp_object_cache;
71
72
		$cache_dirty_count = $this->_dirty_objects_count($wp_object_cache->dirty_objects);
73
		$cache_dirty_delta = $this->array_sub($cache_dirty_count, $item['cache_dirty_objects']);
74
75
		if (isset($this->profile[$name])) {
76
			$this->profile[$name]['time'] += $time;
77
			$this->profile[$name]['calls'] ++;
78
			$this->profile[$name]['cache_cold_hits'] += ($wp_object_cache->cold_cache_hits - $item['cache_cold_hits']);
79
			$this->profile[$name]['cache_warm_hits'] += ($wp_object_cache->warm_cache_hits - $item['cache_warm_hits']);
80
			$this->profile[$name]['cache_misses'] += ($wp_object_cache->cache_misses - $item['cache_misses']);
81
			$this->profile[$name]['cache_dirty_objects'] = array_add( $this->profile[$name]['cache_dirty_objects'], $cache_dirty_delta) ;
82
			$this->profile[$name]['actions'] = array_add( $this->profile[$name]['actions'], $item['actions'] );
83
			$this->profile[$name]['filters'] = array_add( $this->profile[$name]['filters'], $item['filters'] );
84
			$this->profile[$name]['queries'] = array_add( $this->profile[$name]['queries'], $item['queries'] );
85
			#$this->_query_summary($item['queries'], $this->profile[$name]['queries']);
0 ignored issues
show
Unused Code Comprehensibility introduced by
86% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
86
87
		}
88
		else {
89
			$queries = array();
90
			$this->_query_summary($item['queries'], $queries);
91
			$this->profile[$name] = array(
92
				'time' => $time,
93
				'calls' => 1,
94
				'cache_cold_hits' => ($wp_object_cache->cold_cache_hits - $item['cache_cold_hits']),
95
				'cache_warm_hits' => ($wp_object_cache->warm_cache_hits - $item['cache_warm_hits']),
96
				'cache_misses' => ($wp_object_cache->cache_misses - $item['cache_misses']),
97
				'cache_dirty_objects' => $cache_dirty_delta,
98
				'actions' => $item['actions'],
99
				'filters' => $item['filters'],
100
#				'queries' => $item['queries'],
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
101
				'queries' => $queries,
102
			);
103
		}
104
105
		if (!$this->stack) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->stack of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
106
			remove_filter('all', array($this, 'log_filter'));
107
		}
108
	}
109
110
	function microtime($since = 0.0) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
111
		list($usec, $sec) = explode(' ', microtime());
112
		return (float)$sec + (float)$usec - $since;
113
	}
114
115
	function log_filter($tag) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
116
		if ($this->stack) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->stack of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
117
			global $wp_actions;
118
			if ($tag == end($wp_actions))
119
				@$this->stack[count($this->stack)-1]['actions'][$tag] ++;
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
120
			else
121
				@$this->stack[count($this->stack)-1]['filters'][$tag] ++;
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
122
		}
123
		return $arg;
0 ignored issues
show
Bug introduced by
The variable $arg does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
124
	}
125
126
	function log_action($tag) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
127
		if ($this->stack)
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->stack of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
128
			@$this->stack[count($this->stack)-1]['actions'][$tag] ++;
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
129
	}
130
131
	function _current_action() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
132
		global $wp_actions;
133
		return $wp_actions[count($wp_actions)-1];
134
	}
135
136
	function results() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
137
		return $this->profile;
138
	}
139
140
	function _query_summary($queries, &$out) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
141
		foreach ($queries as $q) {
142
			$sql = $q[0];
143
			$sql = preg_replace('/(WHERE \w+ =) \d+/', '$1 x', $sql);
144
			$sql = preg_replace('/(WHERE \w+ =) \'\[-\w]+\'/', '$1 \'xxx\'', $sql);
145
146
			@$out[$sql] ++;
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
147
		}
148
		asort($out);
149
		return;
150
	}
151
152
	function _query_count($queries) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
153
		// this requires the savequeries patch at https://core.trac.wordpress.org/ticket/5218
154
		$out = array();
155
		foreach ($queries as $q) {
156
			if (empty($q[2]))
157
				@$out['unknown'] ++;
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
158
			else
159
				@$out[$q[2]] ++;
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
160
		}
161
		return $out;
162
	}
163
164
	function _dirty_objects_count($dirty_objects) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
165
		$out = array();
166
		foreach (array_keys($dirty_objects) as $group)
167
			$out[$group] = count($dirty_objects[$group]);
168
		return $out;
169
	}
170
171
	function array_add($a, $b) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
172
		$out = $a;
173
		foreach (array_keys($b) as $key)
174
			if (array_key_exists($key, $out))
175
				$out[$key] += $b[$key];
176
			else
177
				$out[$key] = $b[$key];
178
		return $out;
179
	}
180
181
	function array_sub($a, $b) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
182
		$out = $a;
183
		foreach (array_keys($b) as $key)
184
			if (array_key_exists($key, $b))
185
				$out[$key] -= $b[$key];
186
		return $out;
187
	}
188
189
	function print_summary() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
190
		$results = $this->results();
191
192
		printf("\nname                      calls   time action filter   warm   cold misses  dirty\n");
193
		foreach ($results as $name=>$stats) {
194
			printf("%24.24s %6d %6.4f %6d %6d %6d %6d %6d %6d\n", $name, $stats['calls'], $stats['time'], array_sum($stats['actions']), array_sum($stats['filters']), $stats['cache_warm_hits'], $stats['cache_cold_hits'], $stats['cache_misses'], array_sum($stats['cache_dirty_objects']));
195
		}
196
	}
197
}
198
199
global $wppf;
200
$wppf = new WPProfiler();
201
202
function wppf_start($name) {
203
	$GLOBALS['wppf']->start($name);
204
}
205
206
function wppf_stop() {
207
	$GLOBALS['wppf']->stop();
208
}
209
210
function wppf_results() {
211
	return $GLOBALS['wppf']->results();
212
}
213
214
function wppf_print_summary() {
215
	$GLOBALS['wppf']->print_summary();
216
}
217
218
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...