1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Cauditor; |
4
|
|
|
|
5
|
|
|
/** |
6
|
|
|
* @author Matthias Mullie <[email protected]> |
7
|
|
|
* @copyright Copyright (c) 2016, Matthias Mullie. All rights reserved. |
8
|
|
|
* @license LICENSE MIT |
9
|
|
|
*/ |
10
|
|
|
class Aggregator |
11
|
|
|
{ |
12
|
|
|
/** |
13
|
|
|
* @var array |
14
|
|
|
*/ |
15
|
|
|
protected $metrics; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* @var float[][] |
19
|
|
|
*/ |
20
|
|
|
protected $flat; |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* @param array $metrics An AnalyzerInterface::execute result |
24
|
|
|
*/ |
25
|
|
|
public function __construct($metrics) |
26
|
|
|
{ |
27
|
|
|
$this->metrics = $metrics; |
28
|
|
|
} |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* Get metric averages. |
32
|
|
|
* |
33
|
|
|
* @return float[] |
34
|
|
|
*/ |
35
|
|
|
public function average() |
36
|
|
|
{ |
37
|
|
|
$flat = $this->flatten(); |
38
|
|
|
|
39
|
|
|
$avg = array(); |
40
|
|
|
foreach ($flat as $metric => $values) { |
41
|
|
|
$avg[$metric] = (float) number_format(array_sum($values) / count($values), 2, '.', ''); |
42
|
|
|
} |
43
|
|
|
|
44
|
|
|
return $avg; |
45
|
|
|
} |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* Get metric minima. |
49
|
|
|
* |
50
|
|
|
* @return float[] |
51
|
|
|
*/ |
52
|
|
|
public function min() |
53
|
|
|
{ |
54
|
|
|
$flat = $this->flatten(); |
55
|
|
|
|
56
|
|
|
return array_map('min', $flat); |
57
|
|
|
} |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* Get metric maxima. |
61
|
|
|
* |
62
|
|
|
* @return float[] |
63
|
|
|
*/ |
64
|
|
|
public function max() |
65
|
|
|
{ |
66
|
|
|
$flat = $this->flatten(); |
67
|
|
|
|
68
|
|
|
return array_map('max', $flat); |
69
|
|
|
} |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* Get weighed metric averages, where the bigger a method/class is, the more |
73
|
|
|
* it's metric value will count towards the result. |
74
|
|
|
* |
75
|
|
|
* @return float[] |
76
|
|
|
*/ |
77
|
|
|
public function weigh() |
78
|
|
|
{ |
79
|
|
|
$flat = $this->flatten(); |
80
|
|
|
|
81
|
|
|
$weighed = array(); |
82
|
|
|
foreach ($flat as $metric => $data) { |
83
|
|
|
$weighed[$metric] = 0; |
84
|
|
|
$relevant = 0; |
85
|
|
|
foreach ($data as $name => $value) { |
86
|
|
|
$loc = isset($flat['loc'][$name]) ? $flat['loc'][$name] : 0; |
87
|
|
|
$weighed[$metric] += $value * $loc; |
88
|
|
|
$relevant += $loc; |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
$weighed[$metric] = $weighed[$metric] / ($relevant ?: 1); |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
return $weighed; |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* Flatten metrics into [metric => [value1, value1, value3]] array. |
99
|
|
|
* |
100
|
|
|
* @return float[][] |
101
|
|
|
*/ |
102
|
|
|
protected function flatten() |
103
|
|
|
{ |
104
|
|
|
if (!$this->flat) { |
|
|
|
|
105
|
|
|
$this->flat = $this->recurse($this->metrics); |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
return $this->flat; |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* @param array $metrics |
113
|
|
|
* |
114
|
|
|
* @return float[][] |
115
|
|
|
*/ |
116
|
|
|
protected function recurse(array $metrics) |
117
|
|
|
{ |
118
|
|
|
$flat = array(); |
119
|
|
|
$metrics = (array) $metrics; |
120
|
|
|
|
121
|
|
|
foreach ($metrics as $metric => $value) { |
122
|
|
|
// name & children are meta data, not metrics |
123
|
|
|
if (!in_array($metric, array('name', 'children'))) { |
124
|
|
|
$name = isset($metrics['name']) ? $metrics['name'] : ''; |
125
|
|
|
$flat[$metric][$name] = $value; |
126
|
|
|
} |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
if (isset($metrics['children'])) { |
130
|
|
|
foreach ($metrics['children'] as $child) { |
131
|
|
|
$childTotals = $this->recurse($child); |
132
|
|
|
$flat = array_merge_recursive($flat, $childTotals); |
133
|
|
|
} |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
foreach ($flat as $metric => $data) { |
137
|
|
|
// array_merge_recursive will merge into an array of values if there |
138
|
|
|
// are multiple things with the same name, in which case we'll just |
139
|
|
|
// go with the last occurrence |
140
|
|
|
$flat[$metric] = array_map(function ($value) { |
141
|
|
|
return is_array($value) ? array_pop($value) : $value; |
142
|
|
|
}, $flat[$metric]); |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
return $flat; |
146
|
|
|
} |
147
|
|
|
} |
148
|
|
|
|
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.