Completed
Pull Request — master (#608)
by
unknown
17:51
created

MathFormats::min_function()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
/**
4
 * Various mathematical functions - sum, product, average, min, max, median, variance, samplevariance, samplestandarddeviation, standarddeviation, range, quartillower, quartilupper, quartillower.exc, quartilupper.exc, interquartilerange, interquartilerange.exc, mode and interquartilemean
5
 *
6
 * @licence GNU GPL v3+
7
 *
8
 * @author Jeroen De Dauw < [email protected] >
9
 * @author Yaron Koren
10
 * @author Nathan Yergler
11
 * @author Florian Breitenlacher
12
 */
13
14
class MathFormats
15
{
16 1
	public static function max_function(array $numbers)
17
	{
18
		// result
19 1
		return max($numbers);
20
	}
21
22 1
	public static function min_function(array $numbers)
23
	{
24
		// result
25 1
		return min($numbers);
26
	}
27
28 1
	public static function sum_function(array $numbers)
29
	{
30
		// result
31 1
		return array_sum($numbers);
32
	}
33
34 1
	public static function product_function(array $numbers)
35
	{
36
		// result
37 1
		return array_product($numbers);
38
	}
39
40 1
	public static function average_function(array $numbers)
41
	{
42
		// result
43 1
		return array_sum($numbers) / count($numbers);
44
	}
45
46 1
	public static function median_function(array $numbers)
47
	{
48 1
		sort( $numbers, SORT_NUMERIC );
49
		// get position
50 1
		$position = (count($numbers) + 1 ) / 2 - 1;
51
		// result
52 1
		return ( $numbers[ceil($position)] + $numbers[floor($position)]) / 2;
53
	}
54
55
	public static function variance_function(array $numbers)
56
	{
57
		// average
58
		$average = MathFormats::average_function($numbers);
59
		// space
60
		$space = NULL;
61
		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...
62
		{
63
			$space += pow($numbers[$i], 2);
64
		}
65
		// result
66
		return ($space / count($numbers) - pow($average, 2));
67
	}
68
69
	public static function samplevariance_function(array $numbers)
70
	{
71
		// average
72
		$average = MathFormats::average_function($numbers);
73
		// space
74
		$space = NULL;
75
		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...
76
		{
77
			$space += pow(($numbers[$i] - $average), 2);
78
		}
79
		// result
80
		return ($space / (count($numbers) - 1));
81
	}
82
83
	public static function standarddeviation_function(array $numbers)
84
	{
85
		// average
86
		$average = MathFormats::average_function($numbers);
87
		// space
88
		$space = NULL;
89
		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...
90
		{
91
			$space += pow(($numbers[$i] - $average), 2);
92
		}
93
		// result
94
		return sqrt($space / (count($numbers) - 1));
95
	}
96
97
	public static function samplestandarddeviation_function(array $numbers)
98
	{
99
		// average
100
		$average = MathFormats::average_function($numbers);
101
		// space
102
		$space = NULL;
103
		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...
104
		{
105
			$space += pow($numbers[$i], 2);
106
		}
107
		// result
108
		return sqrt($space / count($numbers) - pow($average, 2));
109
	}
110
111
	public static function range_function(array $numbers)
112
	{
113
		// result
114
		return (max($numbers) - min($numbers));
115
	}
116
117
	public static function quartillower_inc_function(array $numbers)
118
	{
119
		sort($numbers, SORT_NUMERIC);
120
		// get position
121
		$Q1_position = ((sizeof($numbers) - 1) * 0.25);
122
		// check if position is between two numbers
123
		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...
124
		{
125
			$Q1_position_y = floor($Q1_position);
126
			$Q1_position_x = ceil($Q1_position);
127
			// result
128
			return ($numbers[$Q1_position_y] + ($numbers[$Q1_position_x] - $numbers[$Q1_position_y]) * 0.25);
129
		}
130
		else
131
		{
132
			// result
133
			return $numbers[$Q1_position];
134
		}
135
	}
136
137
	public static function quartilupper_inc_function(array $numbers)
138
	{
139
		sort($numbers, SORT_NUMERIC);
140
		// get position
141
		$Q3_position = ((sizeof($numbers) - 1) * 0.75);
142
		// check if position is between two numbers
143
		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...
144
		{
145
			$Q3_position_y = floor($Q3_position);
146
			$Q3_position_x = ceil($Q3_position);
147
			// result
148
			return ($numbers[$Q3_position_y] + ($numbers[$Q3_position_x] - $numbers[$Q3_position_y]) * 0.75);
149
		}
150
		else
151
		{
152
			// result
153
			return $numbers[$Q3_position];
154
		}
155
	}
156
157
	public static function quartillower_exc_function(array $numbers)
158
	{
159
		sort($numbers, SORT_NUMERIC);
160
		// get position
161
		$Q1_position = ((sizeof($numbers) + 1) * 0.25);
162
		// check if position is between two numbers
163
		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...
164
		{
165
			$Q1_position_y = floor($Q1_position)-1;
166
			$Q1_position_x = ceil($Q1_position)-1;
167
			// result
168
			return ($numbers[$Q1_position_y] + ($numbers[$Q1_position_x] - $numbers[$Q1_position_y]) * 0.75);
169
		}
170
		else
171
		{
172
			// result
173
			return $numbers[$Q1_position];
174
		}
175
	}
176
177
	public static function quartilupper_exc_function(array $numbers)
178
	{
179
		sort($numbers, SORT_NUMERIC);
180
		// get position
181
		$Q3_position = ((sizeof($numbers) + 1) * 0.75);
182
		// check if position is between two numbers
183
		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...
184
		{
185
			$Q3_position_y = floor($Q3_position)-1;
186
			$Q3_position_x = ceil($Q3_position)-1;
187
			// result
188
			return ($numbers[$Q3_position_y] + ($numbers[$Q3_position_x] - $numbers[$Q3_position_y]) * 0.25);
189
		}
190
		else
191
		{
192
			// result
193
			return $numbers[$Q3_position];
194
		}
195
	}
196
197
	public static function interquartilerange_inc_function(array $numbers)
198
	{
199
		// result
200
		return MathFormats::quartilupper_inc_function($numbers) - MathFormats::quartillower_inc_function($numbers);
201
	}
202
203
	public static function interquartilerange_exc_function(array $numbers)
204
	{
205
		// result
206
		return MathFormats::quartilupper_exc_function($numbers) - MathFormats::quartillower_exc_function($numbers);
207
	}
208
209
	public static function mode_function(array $numbers)
210
	{
211
		// array temp
212
		$array_temp = array();
213
		// convert array
214
		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...
215
		{
216
			$converted_value = strval($numbers[$i]);
217
			$array_temp += [$i => $converted_value];
218
		}
219
		$array_counted_values = array_count_values($array_temp);
220
		// max
221
		$max = max($array_counted_values);
222
		// count
223
		$count = NULL;
224
		// filter
225
		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...
226
		{
227
			if ($array_counted_values[array_keys($array_counted_values)[$i]] == $max)
228
			{
229
				$count += 1;
230
			}
231
		}
232
		// check if there are more than one max
233
		if($count == 1)
234
		{
235
			// result
236
			return $max;
237
		}
238
	}
239
240
	public static function interquartilemean_function(array $numbers)
241
	{
242
		// sort numbers
243
		sort($numbers,SORT_NUMERIC);
244
		// check if size of numbers is divisible by 4
245
		if(sizeof($numbers)%4 == 0)
246
		{
247
			// split array into 4 groups (2D array)
248
			$array_split = (array_chunk($numbers, sizeof($numbers)/4));
249
			// creating store_string
250
			$store_string = NULL;
251
			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...
252
			{
253
				$store_string += $array_split[1][$i];
254
			}
255
			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...
256
			{
257
				$store_string += $array_split[2][$i];
258
			}
259
			// result
260
			return $store_string/(sizeof($array_split[1])+sizeof($array_split[2]));
261
		}
262
		else
263
		{
264
			// get position of split
265
			$position = sizeof($numbers)/4;
266
			// remove values out of split
267
			for($i = 0; $i < floor($position); $i++)
268
			{
269
				unset($numbers[$i]);
270
				array_pop($numbers);
271
			}
272
			// reset array keys
273
			$store_array = array_merge($numbers);
274
			// add values
275
			$store_values = NULL;
276
			for($i = 1; $i < sizeof($store_array)-1; $i++)
277
			{
278
				$store_values += $store_array[$i];
279
			}
280
			// result
281
			return ($store_values + ((ceil($position) - $position) * ($store_array[0] + $store_array[sizeof($store_array)-1]))) / ($position*2);
282
		}
283
	}
284
}
285
286
class SRFMath extends SMWResultPrinter {
287
288
	/**
289
	 * (non-PHPdoc)
290
	 * @see SMWResultPrinter::getName()
291
	 */
292
	public function getName() {
293
		// Give grep a chance to find the usages:
294 1
		// srf_printername_max, srf_printername_min, srf_printername_sum,
295
		// srf_printername_product, srf_printername_average, srf_printername_median
296 1
		return wfMessage( 'srf_printername_' . $this->mFormat )->text();
297
	}
298 1
299
	/**
300
	 * @see SMWResultPrinter::buildResult
301
	 *
302 1
	 * @since 1.8
303
	 *
304
	 * @param SMWQueryResult $results
305
	 *
306 1
	 * @return string
307 1
	 */
308 1
	protected function buildResult( SMWQueryResult $results ) {
309
310
		$number = $this->getResultText( $results, SMW_OUTPUT_HTML );
311 1
312
		if ( count( $results->getPrintRequests() ) > 1 ) {
313
			$outputformat = $results->getPrintRequests()[1]->getOutputFormat();
314
		} else {
315
			// no mainlabel
316
			$outputformat = $results->getPrintRequests()[0]->getOutputFormat();
317 1
		}
318 1
319
		// if raw-format ("-") than skip formatNum()
320 1
		if ( $outputformat != "-" ) {
321
			$dataValue = \SMW\DataValueFactory::getInstance()->newDataValueByType( '_num' );
322
			$number = $dataValue->getLocalizedFormattedNumber( $number );
323
		}
324 1
325 1
		return (string)$number;
326 1
	}
327
328 1
	/**
329 1
	 * @see SMWResultPrinter::getResultText()
330
	 */
331 1
	protected function getResultText( SMWQueryResult $res, $outputmode ) {
332 1
		$numbers = $this->getNumbers( $res );
333
334 1
		if ( count( $numbers ) == 0 ) {
335 1
			return $this->params['default'];
336
		}
337 1
338 1
		switch ( $this->mFormat ) {
339
			case 'max':
340 1
				return MathFormats::max_function($numbers);
341 1
				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 'min':
343
				return MathFormats::min_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 'sum':
346
				return MathFormats::sum_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 'product':
349
				return MathFormats::product_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 'average':
352
				return MathFormats::average_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 'median':
355
				return MathFormats::median_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 'variance':
358
				return MathFormats::variance_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 'samplevariance':
361
				return MathFormats::samplevariance_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 'samplestandarddeviation':
364
				return MathFormats::samplestandarddeviation_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 'standarddeviation':
367
				return MathFormats::standarddeviation_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 'range':
370
				return MathFormats::range_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 'quartillower':
373
				return MathFormats::quartillower_inc_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 'quartilupper';
376
				return MathFormats::quartilupper_inc_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 'quartillower.exc';
379
				return MathFormats::quartillower_exc_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
			case 'quartilupper.exc';
382
				return MathFormats::quartilupper_exc_function($numbers);
383
				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...
384
			case 'interquartilerange':
385
				return MathFormats::interquartilerange_inc_function($numbers);
386
				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...
387
			case 'interquartilerange.exc';
388
				return MathFormats::interquartilerange_exc_function($numbers);
389
				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...
390 1
			case 'mode';
391 1
				return MathFormats::mode_function($numbers);
392
				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...
393 1
			case 'interquartilemean';
394 1
				return MathFormats::interquartilemean_function($numbers);
395 1
				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...
396 1
		}
397
	}
398
399
	/**
400
	 * @param SMWQueryResult $res
401 1
	 *
402
	 * @return float[]
403
	 */
404
	private function getNumbers( SMWQueryResult $res ) {
405
		$numbers = [];
406
407
		while ( $row = $res->getNext() ) {
408 1
			foreach ( $row as $resultArray ) {
409 1
				foreach ( $resultArray->getContent() as $dataItem ) {
410
					self::addNumbersForDataItem( $dataItem, $numbers );
411 1
				}
412 1
			}
413
		}
414
415
		return $numbers;
416
	}
417
418
	/**
419
	 * @param SMWDataItem $dataItem
420 1
	 * @param float[] $numbers
421
	 */
422
	private function addNumbersForDataItem( SMWDataItem $dataItem, array &$numbers ) {
423
		switch ( $dataItem->getDIType() ) {
424
			case SMWDataItem::TYPE_NUMBER:
425
				$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...
426
				break;
427
			case SMWDataItem::TYPE_CONTAINER:
428
				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...
429
					self::addNumbersForDataItem( $di, $numbers );
430
				}
431
				break;
432
			default:
433
		}
434
	}
435
436
}
437