Completed
Pull Request — master (#604)
by
unknown
05:32
created

MathFormats   A

Complexity

Total Complexity 36

Size/Duplication

Total Lines 257
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Test Coverage

Coverage 12.83%

Importance

Changes 0
Metric Value
wmc 36
lcom 1
cbo 0
dl 0
loc 257
ccs 14
cts 109
cp 0.1283
rs 9.52
c 0
b 0
f 0

19 Methods

Rating   Name   Duplication   Size   Complexity  
A max_function() 0 5 1
A min_function() 0 5 1
A sum_function() 0 5 1
A pruduct_function() 0 5 1
A average_function() 0 5 1
A median_function() 0 8 1
A variance_function() 0 13 2
A samplevariance_function() 0 13 2
A standarddeviation_function() 0 13 2
A samplestandarddeviation_function() 0 13 2
A range_function() 0 4 1
A quartillower_inc_function() 0 17 2
A quartilupper_inc_function() 0 17 2
A quartillower_exc_function() 0 17 2
A quartilupper_exc_function() 0 17 2
A interquartilerange_inc_function() 0 4 1
A interquartilerange_exc_function() 0 4 1
A mode_function() 0 29 5
B interquartilemean_function() 0 42 6
1
<?php
2
3
/**
4
 * Various mathematical functions - sum, product, average, min and max.
5
 *
6
 * @licence GNU GPL v3+
7
 *
8
 * @author Jeroen De Dauw < [email protected] >
9
 * @author Yaron Koren
10
 * @author Nathan Yergler
11
 */
12
13
class MathFormats
14
{
15 1
	public static function max_function(array $numbers)
16
	{
17
		// result
18 1
		return max($numbers);
19
	}
20
21 1
	public static function min_function(array $numbers)
22
	{
23
		// result
24 1
		return min($numbers);
25
	}
26
27 1
	public static function sum_function(array $numbers)
28
	{
29
		// result
30 1
		return array_sum($numbers);
31
	}
32
33 1
	public static function pruduct_function(array $numbers)
34
	{
35
		// result
36 1
		return array_product($numbers);
37
	}
38
39 1
	public static function average_function(array $numbers)
40
	{
41
		// result
42 1
		return array_sum($numbers) / count($numbers);
43
	}
44
45 1
	public static function median_function(array $numbers)
46
	{
47 1
		sort( $numbers, SORT_NUMERIC );
48
		// get position
49 1
		$position = (count($numbers) + 1 ) / 2 - 1;
50
		// result
51 1
		return ( $numbers[ceil($position)] + $numbers[floor($position)]) / 2;
52
	}
53
54
	public static function variance_function(array $numbers)
55
	{
56
		// average
57
		$average = MathFormats::average_function($numbers);
58
		// space
59
		$space = NULL;
60
		for($i = 0; $i < count($numbers); $i++)
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
61
		{
62
			$space += pow($numbers[$i], 2);
63
		}
64
		// result
65
		return ($space / count($numbers) - pow($average, 2));
66
	}
67
68
	public static function samplevariance_function(array $numbers)
69
	{
70
		// average
71
		$average = MathFormats::average_function($numbers);
72
		// space
73
		$space = NULL;
74
		for($i = 0; $i < count($numbers); $i++)
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
75
		{
76
			$space += pow(($numbers[$i] - $average), 2);
77
		}
78
		// result
79
		return ($space / (count($numbers) - 1));
80
	}
81
82
	public static function standarddeviation_function(array $numbers)
83
	{
84
		// average
85
		$average = MathFormats::average_function($numbers);
86
		// space
87
		$space = NULL;
88
		for($i = 0; $i < count($numbers); $i++)
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
89
		{
90
			$space += pow(($numbers[$i] - $average), 2);
91
		}
92
		// result
93
		return sqrt($space / (count($numbers) - 1));
94
	}
95
96
	public static function samplestandarddeviation_function(array $numbers)
97
	{
98
		// average
99
		$average = MathFormats::average_function($numbers);
100
		// space
101
		$space = NULL;
102
		for($i = 0; $i < count($numbers); $i++)
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
103
		{
104
			$space += pow($numbers[$i], 2);
105
		}
106
		// result
107
		return sqrt($space / count($numbers) - pow($average, 2));
108
	}
109
110
	public static function range_function(array $numbers)
111
	{
112
		return (max($numbers) - min($numbers));
113
	}
114
115
	public static function quartillower_inc_function(array $numbers)
116
	{
117
		sort($numbers, SORT_NUMERIC);
118
		// get position
119
		$Q1_position = ((sizeof($numbers) - 1) * 0.25);
120
		// check if position is between two numbers
121
		if(is_float($Q1_position) == 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...
122
		{
123
			$Q1_position_y = floor($Q1_position);
124
			$Q1_position_x = ceil($Q1_position);
125
			return ($numbers[$Q1_position_y] + ($numbers[$Q1_position_x] - $numbers[$Q1_position_y]) * 0.25);
126
		}
127
		else
128
		{
129
			return $numbers[$Q1_position];
130
		}
131
	}
132
133
	public static function quartilupper_inc_function(array $numbers)
134
	{
135
		sort($numbers, SORT_NUMERIC);
136
		// get position
137
		$Q3_position = ((sizeof($numbers) - 1) * 0.75);
138
		// check if position is between two numbers
139
		if(is_float($Q3_position) == 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...
140
		{
141
			$Q3_position_y = floor($Q3_position);
142
			$Q3_position_x = ceil($Q3_position);
143
			return ($numbers[$Q3_position_y] + ($numbers[$Q3_position_x] - $numbers[$Q3_position_y]) * 0.75);
144
		}
145
		else
146
		{
147
			return $numbers[$Q3_position];
148
		}
149
	}
150
151
	public static function quartillower_exc_function(array $numbers)
152
	{
153
		sort($numbers, SORT_NUMERIC);
154
		// get position
155
		$Q1_position = ((sizeof($numbers) + 1) * 0.25);
156
		// check if position is between two numbers
157
		if(is_float($Q1_position) == 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...
158
		{
159
			$Q1_position_y = floor($Q1_position)-1;
160
			$Q1_position_x = ceil($Q1_position)-1;
161
			return ($numbers[$Q1_position_y] + ($numbers[$Q1_position_x] - $numbers[$Q1_position_y]) * 0.75);
162
		}
163
		else
164
		{
165
			return $numbers[$Q1_position];
166
		}
167
	}
168
169
	public static function quartilupper_exc_function(array $numbers)
170
	{
171
		sort($numbers, SORT_NUMERIC);
172
		// get position
173
		$Q3_position = ((sizeof($numbers) + 1) * 0.75);
174
		// check if position is between two numbers
175
		if(is_float($Q3_position) == 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...
176
		{
177
			$Q3_position_y = floor($Q3_position)-1;
178
			$Q3_position_x = ceil($Q3_position)-1;
179
			return ($numbers[$Q3_position_y] + ($numbers[$Q3_position_x] - $numbers[$Q3_position_y]) * 0.25);
180
		}
181
		else
182
		{
183
			return $numbers[$Q3_position];
184
		}
185
	}
186
187
	public static function interquartilerange_inc_function(array $numbers)
188
	{
189
		return MathFormats::quartilupper_inc_function($numbers) - MathFormats::quartillower_inc_function($numbers);
190
	}
191
192
	public static function interquartilerange_exc_function(array $numbers)
193
	{
194
		return MathFormats::quartilupper_exc_function($numbers) - MathFormats::quartillower_exc_function($numbers);
195
	}
196
197
	public static function mode_function(array $numbers)
198
	{
199
		// array temp
200
		$array_temp = array();
201
		// convert array
202
		for($i = 0; $i < sizeof($numbers); $i++)
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function sizeof() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
203
		{
204
			$converted_value = strval($numbers[$i]);
205
			$array_temp += [$i => $converted_value];
206
		}
207
		$array_counted_values = array_count_values($array_temp);
208
		// max
209
		$max = max($array_counted_values);
210
		// count
211
		$count = NULL;
212
		// filter
213
		for($i = 0; $i < sizeof($array_counted_values); $i++)
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function sizeof() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
214
		{
215
			if ($array_counted_values[array_keys($array_counted_values)[$i]] == $max)
216
			{
217
				$count += 1;
218
			}
219
		}
220
		// check if there are more than one max
221
		if($count == 1)
222
		{
223
			return $max;
224
		}
225
	}
226
227
	public static function interquartilemean_function(array $numbers)
228
	{
229
		// sort numbers
230
		sort($numbers,SORT_NUMERIC);
231
		// check if size of numbers is divisble by 4
232
		if(sizeof($numbers)%4 == 0)
233
		{
234
			// split array into 4 groups (2D array)
235
			$array_split = (array_chunk($numbers, sizeof($numbers)/4));
236
			// creating store_string
237
			$store_string = NULL;
238
			for($i = 0; $i < sizeof($array_split[1]); $i++)
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function sizeof() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
239
			{
240
				$store_string += $array_split[1][$i];
241
			}
242
			for($i = 0; $i < sizeof($array_split[2]); $i++)
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function sizeof() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
243
			{
244
				$store_string += $array_split[2][$i];
245
			}
246
			return $store_string/(sizeof($array_split[1])+sizeof($array_split[2]));
247
		}
248
		else
249
		{
250
			// get positon of split
251
			$position = sizeof($numbers)/4;
252
			// remove values out of split
253
			for($i = 0; $i < floor($position); $i++)
254
			{
255
				unset($numbers[$i]);
256
				array_pop($numbers);
257
			}
258
			// reset array keys
259
			$store_array = array_merge($numbers);
260
			// add values
261
			$store_values = NULL;
262
			for($i = 1; $i < sizeof($store_array)-1; $i++)
263
			{
264
				$store_values += $store_array[$i];
265
			}
266
			return ($store_values + ((ceil($position) - $position) * ($store_array[0] + $store_array[sizeof($store_array)-1]))) / ($position*2);
267
		}
268
	}
269
}
270
271
class SRFMath extends SMWResultPrinter {
272
273
	/**
274
	 * (non-PHPdoc)
275
	 * @see SMWResultPrinter::getName()
276
	 */
277
	public function getName() {
278
		// Give grep a chance to find the usages:
279
		// srf_printername_max, srf_printername_min, srf_printername_sum,
280
		// srf_printername_product, srf_printername_average, srf_printername_median
281
		return wfMessage( 'srf_printername_' . $this->mFormat )->text();
282
	}
283
284
	/**
285
	 * @see SMWResultPrinter::buildResult
286
	 *
287
	 * @since 1.8
288
	 *
289
	 * @param SMWQueryResult $results
290
	 *
291
	 * @return string
292
	 */
293 1
	protected function buildResult( SMWQueryResult $results ) {
294
295 1
		$number = $this->getResultText( $results, SMW_OUTPUT_HTML );
296
297 1
		if ( count( $results->getPrintRequests() ) > 1 ) {
298
			$outputformat = $results->getPrintRequests()[1]->getOutputFormat();
299
		} else {
300
			// no mainlabel
301 1
			$outputformat = $results->getPrintRequests()[0]->getOutputFormat();
302
		}
303
304
		// if raw-format ("-") than skip formatNum()
305 1
		if ( $outputformat != "-" ) {
306 1
			$dataValue = \SMW\DataValueFactory::getInstance()->newDataValueByType( '_num' );
307 1
			$number = $dataValue->getLocalizedFormattedNumber( $number );
308
		}
309
310 1
		return (string)$number;
311
	}
312
313
	/**
314
	 * @see SMWResultPrinter::getResultText()
315
	 */
316 1
	protected function getResultText( SMWQueryResult $res, $outputmode ) {
317 1
		$numbers = $this->getNumbers( $res );
318
319 1
		if ( count( $numbers ) == 0 ) {
320
			return $this->params['default'];
321
		}
322
323 1
		switch ( $this->mFormat ) {
324 1
			case 'max':
325 1
				return MathFormats::max_function($numbers);
326
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
327 1
			case 'min':
328 1
				return MathFormats::min_function($numbers);
329
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
330 1
			case 'sum':
331 1
				return MathFormats::sum_function($numbers);
332
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
333 1
			case 'product':
334 1
				return MathFormats::pruduct_function($numbers);
335
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
336 1
			case 'average':
337 1
				return MathFormats::average_function($numbers);
338
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
339 1
			case 'median':
340 1
				return MathFormats::median_function($numbers);
341
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
342
			case 'variance':
343
				return MathFormats::variance_function($numbers);
344
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
345
			case 'samplevariance':
346
				return MathFormats::samplevariance_function($numbers);
347
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
348
			case 'samplestandarddeviation':
349
				return MathFormats::samplestandarddeviation_function($numbers);
350
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
351
			case 'standarddeviation':
352
				return MathFormats::standarddeviation_function($numbers);
353
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
354
			case 'range':
355
				return MathFormats::range_function($numbers);
356
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
357
			case 'quartillower':
358
				return MathFormats::quartillower_inc_function($numbers);
359
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
360
			case 'quartilupper';
361
				return MathFormats::quartilupper_inc_function($numbers);
362
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
363
			case 'quartillower.exc';
364
				return MathFormats::quartillower_exc_function($numbers);
365
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
366
			case 'quartilupper.exc';
367
				return MathFormats::quartilupper_exc_function($numbers);
368
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
369
			case 'interquartilerange':
370
				return MathFormats::interquartilerange_inc_function($numbers);
371
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
372
			case 'interquartilerange.exc';
373
				return MathFormats::interquartilerange_exc_function($numbers);
374
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
375
			case 'mode';
376
				return MathFormats::mode_function($numbers);
377
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
378
			case 'interquartilemean';
379
				return MathFormats::interquartilemean_function($numbers);
380
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
381
		}
382
	}
383
384
	/**
385
	 * @param SMWQueryResult $res
386
	 *
387
	 * @return float[]
388
	 */
389 1
	private function getNumbers( SMWQueryResult $res ) {
390 1
		$numbers = [];
391
392 1
		while ( $row = $res->getNext() ) {
393 1
			foreach ( $row as $resultArray ) {
394 1
				foreach ( $resultArray->getContent() as $dataItem ) {
395 1
					self::addNumbersForDataItem( $dataItem, $numbers );
396
				}
397
			}
398
		}
399
400 1
		return $numbers;
401
	}
402
403
	/**
404
	 * @param SMWDataItem $dataItem
405
	 * @param float[] $numbers
406
	 */
407 1
	private function addNumbersForDataItem( SMWDataItem $dataItem, array &$numbers ) {
408 1
		switch ( $dataItem->getDIType() ) {
409
			case SMWDataItem::TYPE_NUMBER:
410 1
				$numbers[] = $dataItem->getNumber();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SMWDataItem as the method getNumber() does only exist in the following sub-classes of SMWDataItem: SMWDINumber. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
411 1
				break;
412
			case SMWDataItem::TYPE_CONTAINER:
413
				foreach ( $dataItem->getDataItems() as $di ) {
0 ignored issues
show
Bug introduced by
The method getDataItems() does not seem to exist on object<SMWDataItem>.

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...
414
					self::addNumbersForDataItem( $di, $numbers );
415
				}
416
				break;
417
			default:
418
		}
419 1
	}
420
421
}
422