Completed
Push — master ( bcd2c2...c3560f )
by Jeroen De
05:57
created

MathFormats::mode_function()   A

Complexity

Conditions 5
Paths 12

Size

Total Lines 29

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
dl 0
loc 29
ccs 0
cts 14
cp 0
rs 9.1448
c 0
b 0
f 0
cc 5
nc 12
nop 1
crap 30
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
 * @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 pruduct_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
		return (max($numbers) - min($numbers));
114
	}
115
116
	public static function quartillower_inc_function(array $numbers)
117
	{
118
		sort($numbers, SORT_NUMERIC);
119
		// get position
120
		$Q1_position = ((sizeof($numbers) - 1) * 0.25);
121
		// check if position is between two numbers
122
		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...
123
		{
124
			$Q1_position_y = floor($Q1_position);
125
			$Q1_position_x = ceil($Q1_position);
126
			return ($numbers[$Q1_position_y] + ($numbers[$Q1_position_x] - $numbers[$Q1_position_y]) * 0.25);
127
		}
128
		else
129
		{
130
			return $numbers[$Q1_position];
131
		}
132
	}
133
134
	public static function quartilupper_inc_function(array $numbers)
135
	{
136
		sort($numbers, SORT_NUMERIC);
137
		// get position
138
		$Q3_position = ((sizeof($numbers) - 1) * 0.75);
139
		// check if position is between two numbers
140
		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...
141
		{
142
			$Q3_position_y = floor($Q3_position);
143
			$Q3_position_x = ceil($Q3_position);
144
			return ($numbers[$Q3_position_y] + ($numbers[$Q3_position_x] - $numbers[$Q3_position_y]) * 0.75);
145
		}
146
		else
147
		{
148
			return $numbers[$Q3_position];
149
		}
150
	}
151
152
	public static function quartillower_exc_function(array $numbers)
153
	{
154
		sort($numbers, SORT_NUMERIC);
155
		// get position
156
		$Q1_position = ((sizeof($numbers) + 1) * 0.25);
157
		// check if position is between two numbers
158
		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...
159
		{
160
			$Q1_position_y = floor($Q1_position)-1;
161
			$Q1_position_x = ceil($Q1_position)-1;
162
			return ($numbers[$Q1_position_y] + ($numbers[$Q1_position_x] - $numbers[$Q1_position_y]) * 0.75);
163
		}
164
		else
165
		{
166
			return $numbers[$Q1_position];
167
		}
168
	}
169
170
	public static function quartilupper_exc_function(array $numbers)
171
	{
172
		sort($numbers, SORT_NUMERIC);
173
		// get position
174
		$Q3_position = ((sizeof($numbers) + 1) * 0.75);
175
		// check if position is between two numbers
176
		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...
177
		{
178
			$Q3_position_y = floor($Q3_position)-1;
179
			$Q3_position_x = ceil($Q3_position)-1;
180
			return ($numbers[$Q3_position_y] + ($numbers[$Q3_position_x] - $numbers[$Q3_position_y]) * 0.25);
181
		}
182
		else
183
		{
184
			return $numbers[$Q3_position];
185
		}
186
	}
187
188
	public static function interquartilerange_inc_function(array $numbers)
189
	{
190
		return MathFormats::quartilupper_inc_function($numbers) - MathFormats::quartillower_inc_function($numbers);
191
	}
192
193
	public static function interquartilerange_exc_function(array $numbers)
194
	{
195
		return MathFormats::quartilupper_exc_function($numbers) - MathFormats::quartillower_exc_function($numbers);
196
	}
197
198
	public static function mode_function(array $numbers)
199
	{
200
		// array temp
201
		$array_temp = array();
202
		// convert array
203
		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...
204
		{
205
			$converted_value = strval($numbers[$i]);
206
			$array_temp += [$i => $converted_value];
207
		}
208
		$array_counted_values = array_count_values($array_temp);
209
		// max
210
		$max = max($array_counted_values);
211
		// count
212
		$count = NULL;
213
		// filter
214
		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...
215
		{
216
			if ($array_counted_values[array_keys($array_counted_values)[$i]] == $max)
217
			{
218
				$count += 1;
219
			}
220
		}
221
		// check if there are more than one max
222
		if($count == 1)
223
		{
224
			return $max;
225
		}
226
	}
227
228
	public static function interquartilemean_function(array $numbers)
229
	{
230
		// sort numbers
231
		sort($numbers,SORT_NUMERIC);
232
		// check if size of numbers is divisble by 4
233
		if(sizeof($numbers)%4 == 0)
234
		{
235
			// split array into 4 groups (2D array)
236
			$array_split = (array_chunk($numbers, sizeof($numbers)/4));
237
			// creating store_string
238
			$store_string = NULL;
239
			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...
240
			{
241
				$store_string += $array_split[1][$i];
242
			}
243
			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...
244
			{
245
				$store_string += $array_split[2][$i];
246
			}
247
			return $store_string/(sizeof($array_split[1])+sizeof($array_split[2]));
248
		}
249
		else
250
		{
251
			// get positon of split
252
			$position = sizeof($numbers)/4;
253
			// remove values out of split
254
			for($i = 0; $i < floor($position); $i++)
255
			{
256
				unset($numbers[$i]);
257
				array_pop($numbers);
258
			}
259
			// reset array keys
260
			$store_array = array_merge($numbers);
261
			// add values
262
			$store_values = NULL;
263
			for($i = 1; $i < sizeof($store_array)-1; $i++)
264
			{
265
				$store_values += $store_array[$i];
266
			}
267
			return ($store_values + ((ceil($position) - $position) * ($store_array[0] + $store_array[sizeof($store_array)-1]))) / ($position*2);
268
		}
269
	}
270
}
271
272
class SRFMath extends SMWResultPrinter {
273
274
	/**
275
	 * (non-PHPdoc)
276
	 * @see SMWResultPrinter::getName()
277
	 */
278
	public function getName() {
279
		// Give grep a chance to find the usages:
280
		// srf_printername_max, srf_printername_min, srf_printername_sum,
281
		// srf_printername_product, srf_printername_average, srf_printername_median
282
		return wfMessage( 'srf_printername_' . $this->mFormat )->text();
283
	}
284
285
	/**
286
	 * @see SMWResultPrinter::buildResult
287
	 *
288
	 * @since 1.8
289
	 *
290
	 * @param SMWQueryResult $results
291
	 *
292
	 * @return string
293
	 */
294 1
	protected function buildResult( SMWQueryResult $results ) {
295
296 1
		$number = $this->getResultText( $results, SMW_OUTPUT_HTML );
297
298 1
		if ( count( $results->getPrintRequests() ) > 1 ) {
299
			$outputformat = $results->getPrintRequests()[1]->getOutputFormat();
300
		} else {
301
			// no mainlabel
302 1
			$outputformat = $results->getPrintRequests()[0]->getOutputFormat();
303
		}
304
305
		// if raw-format ("-") than skip formatNum()
306 1
		if ( $outputformat != "-" ) {
307 1
			$dataValue = \SMW\DataValueFactory::getInstance()->newDataValueByType( '_num' );
308 1
			$number = $dataValue->getLocalizedFormattedNumber( $number );
309
		}
310
311 1
		return (string)$number;
312
	}
313
314
	/**
315
	 * @see SMWResultPrinter::getResultText()
316
	 */
317 1
	protected function getResultText( SMWQueryResult $res, $outputmode ) {
318 1
		$numbers = $this->getNumbers( $res );
319
320 1
		if ( count( $numbers ) == 0 ) {
321
			return $this->params['default'];
322
		}
323
324 1
		switch ( $this->mFormat ) {
325 1
			case 'max':
326 1
				return MathFormats::max_function($numbers);
327
				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...
328 1
			case 'min':
329 1
				return MathFormats::min_function($numbers);
330
				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...
331 1
			case 'sum':
332 1
				return MathFormats::sum_function($numbers);
333
				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...
334 1
			case 'product':
335 1
				return MathFormats::pruduct_function($numbers);
336
				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...
337 1
			case 'average':
338 1
				return MathFormats::average_function($numbers);
339
				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...
340 1
			case 'median':
341 1
				return MathFormats::median_function($numbers);
342
				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...
343
			case 'variance':
344
				return MathFormats::variance_function($numbers);
345
				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...
346
			case 'samplevariance':
347
				return MathFormats::samplevariance_function($numbers);
348
				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...
349
			case 'samplestandarddeviation':
350
				return MathFormats::samplestandarddeviation_function($numbers);
351
				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...
352
			case 'standarddeviation':
353
				return MathFormats::standarddeviation_function($numbers);
354
				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...
355
			case 'range':
356
				return MathFormats::range_function($numbers);
357
				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...
358
			case 'quartillower':
359
				return MathFormats::quartillower_inc_function($numbers);
360
				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...
361
			case 'quartilupper';
362
				return MathFormats::quartilupper_inc_function($numbers);
363
				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...
364
			case 'quartillower.exc';
365
				return MathFormats::quartillower_exc_function($numbers);
366
				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...
367
			case 'quartilupper.exc';
368
				return MathFormats::quartilupper_exc_function($numbers);
369
				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...
370
			case 'interquartilerange':
371
				return MathFormats::interquartilerange_inc_function($numbers);
372
				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...
373
			case 'interquartilerange.exc';
374
				return MathFormats::interquartilerange_exc_function($numbers);
375
				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...
376
			case 'mode';
377
				return MathFormats::mode_function($numbers);
378
				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...
379
			case 'interquartilemean';
380
				return MathFormats::interquartilemean_function($numbers);
381
				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...
382
		}
383
	}
384
385
	/**
386
	 * @param SMWQueryResult $res
387
	 *
388
	 * @return float[]
389
	 */
390 1
	private function getNumbers( SMWQueryResult $res ) {
391 1
		$numbers = [];
392
393 1
		while ( $row = $res->getNext() ) {
394 1
			foreach ( $row as $resultArray ) {
395 1
				foreach ( $resultArray->getContent() as $dataItem ) {
396 1
					self::addNumbersForDataItem( $dataItem, $numbers );
397
				}
398
			}
399
		}
400
401 1
		return $numbers;
402
	}
403
404
	/**
405
	 * @param SMWDataItem $dataItem
406
	 * @param float[] $numbers
407
	 */
408 1
	private function addNumbersForDataItem( SMWDataItem $dataItem, array &$numbers ) {
409 1
		switch ( $dataItem->getDIType() ) {
410
			case SMWDataItem::TYPE_NUMBER:
411 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...
412 1
				break;
413
			case SMWDataItem::TYPE_CONTAINER:
414
				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...
415
					self::addNumbersForDataItem( $di, $numbers );
416
				}
417
				break;
418
			default:
419
		}
420 1
	}
421
422
}
423