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

SRFMath::getNumbers()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 13
ccs 7
cts 7
cp 1
rs 9.8333
c 0
b 0
f 0
cc 4
nc 4
nop 1
crap 4
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
function average_function(array $numbers)
14
{
15
	// average
16
	return array_sum($numbers) / count($numbers);
17
}
18
19
function variance_function(array $numbers)
20
{
21
	// average
22
	$average = average_function($numbers);
23
	// space
24
	$space = NULL;
25
	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...
26
	{
27
		$space += pow($numbers[$i], 2);
28
	}
29
	// result
30
	return ($space / count($numbers) - pow($average, 2));
31
}
32
33
function samplevariance_function(array $numbers)
34
{
35
	// average
36
	$average = average_function($numbers);
37
	// space
38
	$space = NULL;
39
	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...
40
	{
41
		$space += pow(($numbers[$i] - $average), 2);
42
	}
43
	// result
44
	return ($space / (count($numbers) - 1));
45
}
46
47
function standarddeviation_function(array $numbers)
48
{
49
	// average
50
	$average = average_function($numbers);
51
	// space
52
	$space = NULL;
53
	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...
54
	{
55
		$space += pow(($numbers[$i] - $average), 2);
56
	}
57
	// result
58
	return sqrt($space / (count($numbers) - 1));
59
}
60
61
function samplestandarddeviation_function(array $numbers)
62
{
63
	// average
64
	$average = average_function($numbers);
65
	// space
66
	$space = NULL;
67
	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...
68
	{
69
		$space += pow($numbers[$i], 2);
70
	}
71
	// result
72
	return sqrt($space / count($numbers) - pow($average, 2));
73
}
74
75
function range_function(array $numbers)
76
{
77
	return (max($numbers) - min($numbers));
78
}
79
80
function quartillower_inc_function(array $numbers)
81
{
82
	sort($numbers, SORT_NUMERIC);
83
	// get position
84
	$Q1_position = ((sizeof($numbers) - 1) * 0.25);
85
	// check if position is between two numbers
86
	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...
87
	{
88
		$Q1_position_y = floor($Q1_position);
89
		$Q1_position_x = ceil($Q1_position);
90
		return ($numbers[$Q1_position_y] + ($numbers[$Q1_position_x] - $numbers[$Q1_position_y]) * 0.25);
91
	}
92
	else
93
	{
94
		return $numbers[$Q1_position];
95
	}
96
}
97
98
function quartilupper_inc_function(array $numbers)
99
{
100
	sort($numbers, SORT_NUMERIC);
101
	// get position
102
	$Q3_position = ((sizeof($numbers) - 1) * 0.75);
103
	// check if position is between two numbers
104
	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...
105
	{
106
		$Q3_position_y = floor($Q3_position);
107
		$Q3_position_x = ceil($Q3_position);
108
		return ($numbers[$Q3_position_y] + ($numbers[$Q3_position_x] - $numbers[$Q3_position_y]) * 0.75);
109
	}
110
	else
111
	{
112
		return $numbers[$Q3_position];
113
	}
114
}
115
116
function quartillower_exc_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)-1;
125
		$Q1_position_x = ceil($Q1_position)-1;
126
		return ($numbers[$Q1_position_y] + ($numbers[$Q1_position_x] - $numbers[$Q1_position_y]) * 0.75);
127
	}
128
	else
129
	{
130
		return $numbers[$Q1_position];
131
	}
132
}
133
134
function quartilupper_exc_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)-1;
143
		$Q3_position_x = ceil($Q3_position)-1;
144
		return ($numbers[$Q3_position_y] + ($numbers[$Q3_position_x] - $numbers[$Q3_position_y]) * 0.25);
145
	}
146
	else
147
	{
148
		return $numbers[$Q3_position];
149
	}
150
}
151
152
function interquartilerange_inc_function(array $numbers)
153
{
154
	return quartilupper_inc_function($numbers) - quartillower_inc_function($numbers);
155
}
156
157
function interquartilerange_exc_function(array $numbers)
158
{
159
	return quartilupper_exc_function($numbers) - quartillower_exc_function($numbers);
160
}
161
162
function mode_function(array $numbers)
163
{
164
	// array temp
165
	$array_temp = array();
166
	// convert array
167
	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...
168
	{
169
		$converted_value = strval($numbers[$i]);
170
		$array_temp += [$i => $converted_value];
171
	}
172
	$array_counted_values = array_count_values($array_temp);
173
	// max
174
	$max = max($array_counted_values);
175
	// count
176
	$count = NULL;
177
	// filter
178
	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...
179
	{
180
		if ($array_counted_values[array_keys($array_counted_values)[$i]] == $max)
181
		{
182
			$count += 1;
183
		}
184
	}
185
	// check if there are more than one max
186
	if($count == 1)
187
	{
188
		return $max;
189
	}
190
}
191
192
function interquartilemean_function(array $numbers)
193
{
194
	// sort numbers
195
	sort($numbers,SORT_NUMERIC);
196
	// check if size of numbers is divisble by 4
197
	if(sizeof($numbers)%4 == 0)
198
	{
199
		// split array into 4 groups (2D array)
200
		$array_split = (array_chunk($numbers, sizeof($numbers)/4));
201
		// creating store_string
202
		$store_string = NULL;
203
		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...
204
		{
205
			$store_string += $array_split[1][$i];
206
		}
207
		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...
208
		{
209
			$store_string += $array_split[2][$i];
210
		}
211
		return $store_string/(sizeof($array_split[1])+sizeof($array_split[2]));
212
	}
213
	else
214
	{
215
		// get positon of split
216
		$position = sizeof($numbers)/4;
217
		// remove values out of split
218
		for($i = 0; $i < floor($position); $i++)
219
		{
220
			unset($numbers[$i]);
221
			array_pop($numbers);
222
		}
223
		// reset array keys
224
		$store_array = array_merge($numbers);
225
		// add values
226
		$store_values = NULL;
227
		for($i = 1; $i < sizeof($store_array)-1; $i++)
228
		{
229
			$store_values += $store_array[$i];
230
		}
231
		return ($store_values + ((ceil($position) - $position) * ($store_array[0] + $store_array[sizeof($store_array)-1]))) / ($position*2);
232
	}
233
}
234
235
class SRFMath extends SMWResultPrinter {
236
237
	/**
238
	 * (non-PHPdoc)
239
	 * @see SMWResultPrinter::getName()
240
	 */
241
	public function getName() {
242
		// Give grep a chance to find the usages:
243
		// srf_printername_max, srf_printername_min, srf_printername_sum,
244
		// srf_printername_product, srf_printername_average, srf_printername_median
245
		return wfMessage( 'srf_printername_' . $this->mFormat )->text();
246
	}
247
248
	/**
249
	 * @see SMWResultPrinter::buildResult
250
	 *
251
	 * @since 1.8
252
	 *
253
	 * @param SMWQueryResult $results
254
	 *
255
	 * @return string
256
	 */
257 1
	protected function buildResult( SMWQueryResult $results ) {
258
259 1
		$number = $this->getResultText( $results, SMW_OUTPUT_HTML );
260
261 1
		if ( count( $results->getPrintRequests() ) > 1 ) {
262
			$outputformat = $results->getPrintRequests()[1]->getOutputFormat();
263
		} else {
264
			// no mainlabel
265 1
			$outputformat = $results->getPrintRequests()[0]->getOutputFormat();
266
		}
267
268
		// if raw-format ("-") than skip formatNum()
269 1
		if ( $outputformat != "-" ) {
270 1
			$dataValue = \SMW\DataValueFactory::getInstance()->newDataValueByType( '_num' );
271 1
			$number = $dataValue->getLocalizedFormattedNumber( $number );
272
		}
273
274 1
		return (string)$number;
275
	}
276
277
	/**
278
	 * @see SMWResultPrinter::getResultText()
279
	 */
280 1
	protected function getResultText( SMWQueryResult $res, $outputmode ) {
281 1
		$numbers = $this->getNumbers( $res );
282
283 1
		if ( count( $numbers ) == 0 ) {
284
			return $this->params['default'];
285
		}
286
287 1
		switch ( $this->mFormat ) {
288 1
			case 'max':
289 1
				return max( $numbers );
290
				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...
291 1
			case 'min':
292 1
				return min( $numbers );
293
				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...
294 1
			case 'sum':
295 1
				return array_sum( $numbers );
296
				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...
297 1
			case 'product':
298 1
				return array_product( $numbers );
299
				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...
300 1
			case 'average':
301 1
				return array_sum( $numbers ) / count( $numbers );
302
				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...
303 1
			case 'median':
304 1
				sort( $numbers, SORT_NUMERIC );
305 1
				$position = ( count( $numbers ) + 1 ) / 2 - 1;
306 1
				return ( $numbers[ceil( $position )] + $numbers[floor( $position )] ) / 2;
307
				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...
308
			case 'variance':
309
				return variance_function($numbers);
310
				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...
311
			case 'samplevariance':
312
				return samplevariance_function($numbers);
313
				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...
314
			case 'samplestandarddeviation':
315
				return samplestandarddeviation_function($numbers);
316
				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...
317
			case 'standarddeviation':
318
				return standarddeviation_function($numbers);
319
				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...
320
			case 'range':
321
				return range_function($numbers);
322
				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...
323
			case 'quartillower':
324
				return quartillower_inc_function($numbers);
325
				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...
326
			case 'quartilupper';
327
				return quartilupper_inc_function($numbers);
328
				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...
329
			case 'quartillower.exc';
330
				return quartillower_exc_function($numbers);
331
				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...
332
			case 'quartilupper.exc';
333
				return quartilupper_exc_function($numbers);
334
				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...
335
			case 'interquartilerange':
336
				return interquartilerange_inc_function($numbers);
337
				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...
338
			case 'interquartilerange.exc';
339
				return interquartilerange_exc_function($numbers);
340
				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...
341
			case 'mode';
342
				return mode_function($numbers);
343
				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...
344
			case 'interquartilemean';
345
				return interquartilemean_function($numbers);
346
				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...
347
		}
348
	}
349
350
	/**
351
	 * @param SMWQueryResult $res
352
	 *
353
	 * @return float[]
354
	 */
355 1
	private function getNumbers( SMWQueryResult $res ) {
356 1
		$numbers = [];
357
358 1
		while ( $row = $res->getNext() ) {
359 1
			foreach ( $row as $resultArray ) {
360 1
				foreach ( $resultArray->getContent() as $dataItem ) {
361 1
					self::addNumbersForDataItem( $dataItem, $numbers );
362
				}
363
			}
364
		}
365
366 1
		return $numbers;
367
	}
368
369
	/**
370
	 * @param SMWDataItem $dataItem
371
	 * @param float[] $numbers
372
	 */
373 1
	private function addNumbersForDataItem( SMWDataItem $dataItem, array &$numbers ) {
374 1
		switch ( $dataItem->getDIType() ) {
375
			case SMWDataItem::TYPE_NUMBER:
376 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...
377 1
				break;
378
			case SMWDataItem::TYPE_CONTAINER:
379
				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...
380
					self::addNumbersForDataItem( $di, $numbers );
381
				}
382
				break;
383
			default:
384
		}
385 1
	}
386
387
}
388