These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | use SMW\Highlighter; |
||
4 | use SMW\IntlNumberFormatter; |
||
5 | use SMW\Localizer; |
||
6 | use SMW\DataValues\ValueFormatters\DataValueFormatter; |
||
7 | |||
8 | /** |
||
9 | * @ingroup SMWDataValues |
||
10 | */ |
||
11 | |||
12 | /** |
||
13 | * This datavalue implements numerical datavalues, and supports optional |
||
14 | * unit conversions. It parses and manages unit strings, since even plain |
||
15 | * numbers may have (not further specified) units that are stored. However, |
||
16 | * only subclasses implement full unit conversion by extending the methods |
||
17 | * convertToMainUnit() and makeConversionValues(). |
||
18 | * |
||
19 | * Units work as follows: a unit is a string, but many such strings might |
||
20 | * refer to the same unit of measurement. There is always one string, that |
||
21 | * canonically represents the unit, and we will call this version of writing |
||
22 | * the unit the /unit id/. IDs for units are needed for tasks like duplicate |
||
23 | * avoidance. If no conversion information is given, any unit is its own ID. |
||
24 | * In any case, units are /normalised/, i.e. given a more standardised meaning |
||
25 | * before being processed. All units, IDs or otherwise, should be suitable for |
||
26 | * printout in wikitext, and main IDs should moreover be suitable for printout |
||
27 | * in HTML. |
||
28 | * |
||
29 | * Subclasses that support unit conversion may interpret the output format set |
||
30 | * via setOutputFormat() to allow a unit to be selected for display. Note that |
||
31 | * this setting does not affect the internal representation of the value |
||
32 | * though. So chosing a specific output format will change the behavior of |
||
33 | * output functions like getLongWikiText(), but not of functions that access |
||
34 | * the value itself, such as getUnit() or getDBKeys(). |
||
35 | * |
||
36 | * @author Markus Krötzsch |
||
37 | * @ingroup SMWDataValues |
||
38 | * |
||
39 | * @todo Wiki-HTML-conversion for unit strings must be revisited, as the current |
||
40 | * solution might be unsafe. |
||
41 | */ |
||
42 | class SMWNumberValue extends SMWDataValue { |
||
43 | |||
44 | /** |
||
45 | * Array with entries unit=>value, mapping a normalized unit to the |
||
46 | * converted value. Used for conversion tooltips. |
||
47 | * @var array |
||
48 | */ |
||
49 | protected $m_unitvalues; |
||
50 | |||
51 | /** |
||
52 | * Whether the unit is preferred as prefix or not |
||
53 | * |
||
54 | * @var array |
||
55 | */ |
||
56 | protected $prefixalUnitPreference = array(); |
||
57 | |||
58 | /** |
||
59 | * Canonical identifier for the unit that the user gave as input. Used |
||
60 | * to avoid printing this in conversion tooltips again. If the |
||
61 | * outputformat was set to show another unit, then the values of |
||
62 | * $m_caption and $m_unitin will be updated as if the formatted string |
||
63 | * had been the original user input, i.e. the two values reflect what |
||
64 | * is currently printed. |
||
65 | * @var string |
||
66 | */ |
||
67 | protected $m_unitin; |
||
68 | |||
69 | /** |
||
70 | * @var integer|null |
||
71 | */ |
||
72 | protected $precision = null; |
||
73 | |||
74 | /** |
||
75 | * @var IntlNumberFormatter |
||
76 | */ |
||
77 | private $intlNumberFormatter = null; |
||
78 | |||
79 | /** |
||
80 | * @since 2.4 |
||
81 | * |
||
82 | * @param string $typeid |
||
83 | */ |
||
84 | 46 | public function __construct( $typeid = '' ) { |
|
85 | 46 | parent::__construct( $typeid ); |
|
86 | 46 | $this->intlNumberFormatter = IntlNumberFormatter::getInstance(); |
|
87 | 46 | $this->intlNumberFormatter->initialize(); |
|
88 | 46 | } |
|
89 | |||
90 | /** |
||
91 | * Parse a string of the form "number unit" where unit is optional. The |
||
92 | * results are stored in the $number and $unit parameters. Returns an |
||
93 | * error code. |
||
94 | * @param $value string to parse |
||
95 | * @param $number call-by-ref parameter that will be set to the numerical value |
||
96 | * @param $unit call-by-ref parameter that will be set to the "unit" string (after the number) |
||
97 | * @return integer 0 (no errors), 1 (no number found at all), 2 (number |
||
98 | * too large for this platform) |
||
99 | */ |
||
100 | 44 | public function parseNumberValue( $value, &$number, &$unit, &$asPrefix = false ) { |
|
101 | |||
102 | 44 | $intlNumberFormatter = $this->getNumberFormatter(); |
|
103 | |||
104 | // Parse to find $number and (possibly) $unit |
||
105 | 44 | $kiloseparator = $intlNumberFormatter->getSeparator( |
|
106 | 44 | IntlNumberFormatter::THOUSANDS_SEPARATOR, |
|
107 | 44 | IntlNumberFormatter::CONTENT_LANGUAGE |
|
108 | ); |
||
109 | |||
110 | 44 | $decseparator = $intlNumberFormatter->getSeparator( |
|
111 | 44 | IntlNumberFormatter::DECIMAL_SEPARATOR, |
|
112 | 44 | IntlNumberFormatter::CONTENT_LANGUAGE |
|
113 | ); |
||
114 | |||
115 | // #753 |
||
116 | $regex = '/([-+]?\s*(?:' . |
||
117 | // Either numbers like 10,000.99 that start with a digit |
||
118 | 44 | '\d+(?:\\' . $kiloseparator . '\d\d\d)*(?:\\' . $decseparator . '\d+)?' . |
|
119 | // or numbers like .001 that start with the decimal separator |
||
120 | 44 | '|\\' . $decseparator . '\d+' . |
|
121 | 44 | ')\s*(?:[eE][-+]?\d+)?)/u'; |
|
122 | |||
123 | 44 | $parts = preg_split( |
|
124 | $regex, |
||
125 | 44 | trim( str_replace( array( ' ', ' ', ' ', ' ' ), '', $value ) ), |
|
126 | 44 | 2, |
|
127 | 44 | PREG_SPLIT_DELIM_CAPTURE |
|
128 | ); |
||
129 | |||
130 | 44 | if ( count( $parts ) >= 2 ) { |
|
131 | 43 | $numstring = str_replace( $kiloseparator, '', preg_replace( '/\s*/u', '', $parts[1] ) ); // simplify |
|
132 | 43 | if ( $decseparator != '.' ) { |
|
133 | 2 | $numstring = str_replace( $decseparator, '.', $numstring ); |
|
134 | } |
||
135 | 43 | list( $number ) = sscanf( $numstring, "%f" ); |
|
136 | 43 | if ( count( $parts ) >= 3 ) { |
|
137 | 43 | $asPrefix = $parts[0] !== ''; |
|
138 | 43 | $unit = $this->normalizeUnit( $parts[0] !== '' ? $parts[0] : $parts[2] ); |
|
139 | } |
||
140 | } |
||
141 | |||
142 | 44 | if ( ( count( $parts ) == 1 ) || ( $numstring === '' ) ) { // no number found |
|
0 ignored issues
–
show
|
|||
143 | 2 | return 1; |
|
144 | 43 | } elseif ( is_infinite( $number ) ) { // number is too large for this platform |
|
145 | return 2; |
||
146 | } else { |
||
147 | 43 | return 0; |
|
148 | } |
||
149 | } |
||
150 | |||
151 | /** |
||
152 | * @see DataValue::parseUserValue |
||
153 | */ |
||
154 | 45 | protected function parseUserValue( $value ) { |
|
155 | // Set caption |
||
156 | 45 | if ( $this->m_caption === false ) { |
|
157 | 45 | $this->m_caption = $value; |
|
158 | } |
||
159 | |||
160 | 45 | if ( $value !== '' && $value{0} === ':' ) { |
|
161 | 1 | $this->addErrorMsg( array( 'smw-datavalue-invalid-number', $value ) ); |
|
162 | 1 | return; |
|
163 | } |
||
164 | |||
165 | 44 | $this->m_unitin = false; |
|
166 | 44 | $this->m_unitvalues = false; |
|
0 ignored issues
–
show
It seems like
false of type false is incompatible with the declared type array of property $m_unitvalues .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..
Loading history...
|
|||
167 | 44 | $number = $unit = ''; |
|
168 | 44 | $error = $this->parseNumberValue( $value, $number, $unit ); |
|
169 | |||
170 | 44 | if ( $error == 1 ) { // no number found |
|
171 | 2 | $this->addErrorMsg( array( 'smw_nofloat', $value ) ); |
|
172 | 43 | } elseif ( $error == 2 ) { // number is too large for this platform |
|
173 | $this->addErrorMsg( array( 'smw_infinite', $value ) ); |
||
174 | 43 | } elseif ( $this->getTypeID() === '_num' && $unit !== '' ) { |
|
175 | 1 | $this->addErrorMsg( array( 'smw-datavalue-number-textnotallowed', $unit, $number ) ); |
|
176 | 43 | } elseif ( $this->convertToMainUnit( $number, $unit ) === false ) { // so far so good: now convert unit and check if it is allowed |
|
177 | 9 | $this->addErrorMsg( array( 'smw_unitnotallowed', $unit ) ); |
|
178 | } // note that convertToMainUnit() also sets m_dataitem if valid |
||
179 | 44 | } |
|
180 | |||
181 | /** |
||
182 | * @see SMWDataValue::loadDataItem() |
||
183 | * @param $dataitem SMWDataItem |
||
184 | * @return boolean |
||
185 | */ |
||
186 | 24 | protected function loadDataItem( SMWDataItem $dataItem ) { |
|
187 | |||
188 | 24 | if ( $dataItem->getDIType() !== SMWDataItem::TYPE_NUMBER ) { |
|
189 | return false; |
||
190 | } |
||
191 | |||
192 | 24 | $this->m_dataitem = $dataItem; |
|
193 | 24 | $this->m_caption = false; |
|
194 | 24 | $this->m_unitin = false; |
|
195 | 24 | $this->makeUserValue(); |
|
196 | 24 | $this->m_unitvalues = false; |
|
0 ignored issues
–
show
It seems like
false of type false is incompatible with the declared type array of property $m_unitvalues .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..
Loading history...
|
|||
197 | |||
198 | 24 | return true; |
|
199 | } |
||
200 | |||
201 | /** |
||
202 | * @see DataValue::setOutputFormat |
||
203 | * |
||
204 | * @param $string $formatstring |
||
205 | */ |
||
206 | 6 | public function setOutputFormat( $formatstring ) { |
|
207 | |||
208 | 6 | if ( $formatstring == $this->m_outformat ) { |
|
209 | return null; |
||
210 | } |
||
211 | |||
212 | // #1591 |
||
213 | 6 | $this->findPreferredLanguageFrom( $formatstring ); |
|
214 | |||
215 | // #1335 |
||
216 | 6 | $this->m_outformat = $this->findPrecisionFrom( $formatstring ); |
|
217 | |||
218 | 6 | if ( $this->isValid() ) { // update caption/unitin for this format |
|
219 | 6 | $this->m_caption = false; |
|
220 | 6 | $this->m_unitin = false; |
|
221 | 6 | $this->makeUserValue(); |
|
222 | } |
||
223 | 6 | } |
|
224 | |||
225 | /** |
||
226 | * @since 2.4 |
||
227 | * |
||
228 | * @return float |
||
229 | */ |
||
230 | 31 | public function getLocalizedFormattedNumber( $value ) { |
|
231 | 31 | return $this->getNumberFormatter()->format( $value, $this->getPreferredDisplayPrecision() ); |
|
232 | } |
||
233 | |||
234 | /** |
||
235 | * @since 2.4 |
||
236 | * |
||
237 | * @return float |
||
238 | */ |
||
239 | 14 | public function getNormalizedFormattedNumber( $value ) { |
|
240 | 14 | return $this->getNumberFormatter()->format( $value, $this->getPreferredDisplayPrecision(), IntlNumberFormatter::VALUE_FORMAT ); |
|
241 | } |
||
242 | |||
243 | /** |
||
244 | * @see DataValue::getShortWikiText |
||
245 | * |
||
246 | * @return string |
||
247 | */ |
||
248 | 30 | public function getShortWikiText( $linker = null ) { |
|
249 | 30 | return $this->getDataValueFormatter()->format( DataValueFormatter::WIKI_SHORT, $linker ); |
|
250 | } |
||
251 | |||
252 | /** |
||
253 | * @see DataValue::getShortHTMLText |
||
254 | * |
||
255 | * @return string |
||
256 | */ |
||
257 | 1 | public function getShortHTMLText( $linker = null ) { |
|
258 | 1 | return $this->getDataValueFormatter()->format( DataValueFormatter::HTML_SHORT, $linker ); |
|
259 | } |
||
260 | |||
261 | /** |
||
262 | * @see DataValue::getLongWikiText |
||
263 | * |
||
264 | * @return string |
||
265 | */ |
||
266 | public function getLongWikiText( $linker = null ) { |
||
267 | return $this->getDataValueFormatter()->format( DataValueFormatter::WIKI_LONG, $linker ); |
||
268 | } |
||
269 | |||
270 | /** |
||
271 | * @see DataValue::getLongHTMLText |
||
272 | * |
||
273 | * @return string |
||
274 | */ |
||
275 | 1 | public function getLongHTMLText( $linker = null ) { |
|
276 | 1 | return $this->getDataValueFormatter()->format( DataValueFormatter::HTML_LONG, $linker ); |
|
277 | } |
||
278 | |||
279 | 18 | public function getNumber() { |
|
280 | 18 | return $this->isValid() ? $this->m_dataitem->getNumber() : 32202; |
|
281 | } |
||
282 | |||
283 | 11 | public function getWikiValue() { |
|
284 | 11 | return $this->getDataValueFormatter()->format( DataValueFormatter::VALUE ); |
|
285 | } |
||
286 | |||
287 | /** |
||
288 | * @see DataVelue::getInfolinks |
||
289 | * |
||
290 | * @return array |
||
291 | */ |
||
292 | public function getInfolinks() { |
||
293 | |||
294 | // When generating an infoLink, use the normalized value without any |
||
295 | // precision limitation |
||
296 | $this->setOption( 'no.displayprecision', true ); |
||
297 | $infoLinks = parent::getInfolinks(); |
||
298 | $this->setOption( 'no.displayprecision', false ); |
||
299 | |||
300 | return $infoLinks; |
||
301 | } |
||
302 | |||
303 | /** |
||
304 | * @since 2.4 |
||
305 | * |
||
306 | * @return string |
||
307 | */ |
||
308 | 27 | public function getCanonicalMainUnit() { |
|
309 | 27 | return $this->m_unitin; |
|
310 | } |
||
311 | |||
312 | /** |
||
313 | * Returns array of converted unit-value-pairs that can be |
||
314 | * printed. |
||
315 | * |
||
316 | * @since 2.4 |
||
317 | * |
||
318 | * @return array |
||
319 | */ |
||
320 | 27 | public function getConvertedUnitValues() { |
|
321 | 27 | $this->makeConversionValues(); |
|
322 | 27 | return $this->m_unitvalues; |
|
323 | } |
||
324 | |||
325 | /** |
||
326 | * Return the unit in which the returned value is to be interpreted. |
||
327 | * This string is a plain UTF-8 string without wiki or html markup. |
||
328 | * The returned value is a canonical ID for the main unit. |
||
329 | * Returns the empty string if no unit is given for the value. |
||
330 | * Overwritten by subclasses that support units. |
||
331 | */ |
||
332 | 8 | public function getUnit() { |
|
333 | 8 | return ''; |
|
334 | } |
||
335 | |||
336 | /** |
||
337 | * @since 2.4 |
||
338 | * |
||
339 | * @param string $unit |
||
340 | * |
||
341 | * @return boolean |
||
342 | */ |
||
343 | 15 | public function hasPrefixalUnitPreference( $unit ) { |
|
344 | 15 | return isset( $this->prefixalUnitPreference[$unit] ) && $this->prefixalUnitPreference[$unit]; |
|
345 | } |
||
346 | |||
347 | /** |
||
348 | * Create links to mapping services based on a wiki-editable message. |
||
349 | * The parameters available to the message are: |
||
350 | * $1: string of numerical value in English punctuation |
||
351 | * $2: string of integer version of value, in English punctuation |
||
352 | * |
||
353 | * @return array |
||
354 | */ |
||
355 | protected function getServiceLinkParams() { |
||
356 | if ( $this->isValid() ) { |
||
357 | return array( strval( $this->m_dataitem->getNumber() ), strval( round( $this->m_dataitem->getNumber() ) ) ); |
||
0 ignored issues
–
show
The return type of
return array(strval($thi...taitem->getNumber()))); (string[] ) is incompatible with the return type of the parent method SMWDataValue::getServiceLinkParams of type boolean .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function
Loading history...
|
|||
358 | } else { |
||
359 | return array(); |
||
0 ignored issues
–
show
The return type of
return array(); (array ) is incompatible with the return type of the parent method SMWDataValue::getServiceLinkParams of type boolean .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function
Loading history...
|
|||
360 | } |
||
361 | } |
||
362 | |||
363 | /** |
||
364 | * Transform a (typically unit-) string into a normalised form, |
||
365 | * so that, e.g., "km²" and "km<sup>2</sup>" do not need to be |
||
366 | * distinguished. |
||
367 | */ |
||
368 | 43 | public function normalizeUnit( $unit ) { |
|
369 | 43 | $unit = str_replace( array( '[[', ']]' ), '', trim( $unit ) ); // allow simple links to be used inside annotations |
|
370 | 43 | $unit = str_replace( array( '²', '<sup>2</sup>' ), '²', $unit ); |
|
371 | 43 | $unit = str_replace( array( '³', '<sup>3</sup>' ), '³', $unit ); |
|
372 | 43 | return smwfXMLContentEncode( $unit ); |
|
373 | } |
||
374 | |||
375 | /** |
||
376 | * Compute the value based on the given input number and unit string. |
||
377 | * If the unit is not supported, return false, otherwise return true. |
||
378 | * This is called when parsing user input, where the given unit value |
||
379 | * has already been normalized. |
||
380 | * |
||
381 | * This class does not support any (non-empty) units, but subclasses |
||
382 | * may overwrite this behavior. |
||
383 | * @param $number float value obtained by parsing user input |
||
384 | * @param $unit string after the numericla user input |
||
385 | * @return boolean specifying if the unit string is allowed |
||
386 | */ |
||
387 | 33 | protected function convertToMainUnit( $number, $unit ) { |
|
388 | 33 | $this->m_dataitem = new SMWDINumber( $number ); |
|
389 | 33 | $this->m_unitin = ''; |
|
390 | 33 | return ( $unit === '' ); |
|
391 | } |
||
392 | |||
393 | /** |
||
394 | * This method creates an array of unit-value-pairs that should be |
||
395 | * printed. Units are the keys and should be canonical unit IDs. |
||
396 | * The result is stored in $this->m_unitvalues. Again, any class that |
||
397 | * requires effort for doing this should first check whether the array |
||
398 | * is already set (i.e. not false) before doing any work. |
||
399 | * Note that the values should be plain numbers. Output formatting is done |
||
400 | * later when needed. Also, it should be checked if the value is valid |
||
401 | * before trying to calculate with its contents. |
||
402 | * This method also must call or implement convertToMainUnit(). |
||
403 | * |
||
404 | * Overwritten by subclasses that support units. |
||
405 | */ |
||
406 | 20 | protected function makeConversionValues() { |
|
407 | 20 | $this->m_unitvalues = array( '' => $this->m_dataitem->getNumber() ); |
|
408 | 20 | } |
|
409 | |||
410 | /** |
||
411 | * This method is used when no user input was given to find the best |
||
412 | * values for m_unitin and m_caption. After conversion, |
||
413 | * these fields will look as if they were generated from user input, |
||
414 | * and convertToMainUnit() will have been called (if not, it would be |
||
415 | * blocked by the presence of m_unitin). |
||
416 | * |
||
417 | * Overwritten by subclasses that support units. |
||
418 | */ |
||
419 | 18 | protected function makeUserValue() { |
|
420 | 18 | $this->m_caption = ''; |
|
421 | |||
422 | 18 | $number = $this->m_dataitem->getNumber(); |
|
423 | |||
424 | // -u is the format for displaying the unit only |
||
425 | 18 | if ( $this->m_outformat == '-u' ) { |
|
426 | $this->m_caption = ''; |
||
427 | 18 | } elseif ( ( $this->m_outformat != '-' ) && ( $this->m_outformat != '-n' ) ) { |
|
428 | 18 | $this->m_caption = $this->getLocalizedFormattedNumber( $number ); |
|
429 | } else { |
||
430 | 2 | $this->m_caption = $this->getNormalizedFormattedNumber( $number ); |
|
431 | } |
||
432 | |||
433 | // no unit ever, so nothing to do about this |
||
434 | 18 | $this->m_unitin = ''; |
|
435 | 18 | } |
|
436 | |||
437 | /** |
||
438 | * Return an array of major unit strings (ids only recommended) supported by |
||
439 | * this datavalue. |
||
440 | * |
||
441 | * Overwritten by subclasses that support units. |
||
442 | */ |
||
443 | public function getUnitList() { |
||
444 | return array( '' ); |
||
445 | } |
||
446 | |||
447 | 31 | protected function getPreferredDisplayPrecision() { |
|
448 | |||
449 | // In case of a value description, don't restrict the value with a display precision |
||
450 | 31 | if ( $this->getProperty() === null || $this->getOptionValueFor( 'value.description' ) || $this->getOptionValueFor( 'no.displayprecision' ) ) { |
|
0 ignored issues
–
show
The expression
$this->getOptionValueFor('value.description') of type string|false is loosely compared to true ; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
Loading history...
The expression
$this->getOptionValueFor('no.displayprecision') of type string|false is loosely compared to true ; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
Loading history...
|
|||
451 | 4 | return false; |
|
452 | } |
||
453 | |||
454 | 31 | if ( $this->precision === null ) { |
|
455 | 31 | $this->precision = $this->getPropertySpecificationLookup()->getDisplayPrecisionFor( |
|
456 | 31 | $this->getProperty() |
|
457 | ); |
||
458 | } |
||
459 | |||
460 | 31 | return $this->precision; |
|
461 | } |
||
462 | |||
463 | 6 | private function findPrecisionFrom( $formatstring ) { |
|
464 | |||
465 | 6 | if ( strpos( $formatstring, '-' ) === false ) { |
|
466 | 4 | return $formatstring; |
|
467 | } |
||
468 | |||
469 | 4 | $parts = explode( '-', $formatstring ); |
|
470 | |||
471 | // Find precision from annotated -p<number of digits> formatstring which |
||
472 | // has priority over a possible _PREC value |
||
473 | 4 | foreach ( $parts as $key => $value ) { |
|
474 | 4 | if ( strpos( $value, 'p' ) !== false && is_numeric( substr( $value, 1 ) ) ) { |
|
475 | 1 | $this->precision = strval( substr( $value, 1 ) ); |
|
0 ignored issues
–
show
It seems like
strval(substr($value, 1)) of type string is incompatible with the declared type integer|null of property $precision .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..
Loading history...
|
|||
476 | 4 | unset( $parts[$key] ); |
|
477 | } |
||
478 | } |
||
479 | |||
480 | // Rebuild formatstring without a possible p element to ensure other |
||
481 | // options can be used in combination such as -n-p2 etc. |
||
482 | 4 | return implode( '-', $parts ); |
|
483 | } |
||
484 | |||
485 | 45 | private function getNumberFormatter() { |
|
486 | |||
487 | 45 | $this->intlNumberFormatter->setOption( |
|
488 | 45 | 'user.language', |
|
489 | 45 | $this->getOptionValueFor( 'user.language' ) |
|
490 | ); |
||
491 | |||
492 | 45 | $this->intlNumberFormatter->setOption( |
|
493 | 45 | 'content.language', |
|
494 | 45 | $this->getOptionValueFor( 'content.language' ) |
|
495 | ); |
||
496 | |||
497 | 45 | $this->intlNumberFormatter->setOption( |
|
498 | 45 | 'separator.thousands', |
|
499 | 45 | $this->getOptionValueFor( 'separator.thousands' ) |
|
500 | ); |
||
501 | |||
502 | 45 | $this->intlNumberFormatter->setOption( |
|
503 | 45 | 'separator.decimal', |
|
504 | 45 | $this->getOptionValueFor( 'separator.decimal' ) |
|
505 | ); |
||
506 | |||
507 | 45 | return $this->intlNumberFormatter; |
|
508 | } |
||
509 | |||
510 | 6 | private function findPreferredLanguageFrom( &$formatstring ) { |
|
511 | // Localized preferred user language |
||
512 | 6 | if ( strpos( $formatstring, 'LOCL' ) !== false && ( $languageCode = Localizer::getLanguageCodeFrom( $formatstring ) ) !== false ) { |
|
513 | 1 | $this->intlNumberFormatter->setOption( |
|
514 | 1 | 'preferred.language', |
|
515 | $languageCode |
||
516 | ); |
||
517 | } |
||
518 | |||
519 | // Remove any remaining |
||
520 | 6 | $formatstring = str_replace( array( '#LOCL', 'LOCL' ), '', $formatstring ); |
|
521 | 6 | } |
|
522 | |||
523 | } |
||
524 |
If you define a variable conditionally, it can happen that it is not defined for all execution paths.
Let’s take a look at an example:
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.
Available Fixes
Check for existence of the variable explicitly:
Define a default value for the variable:
Add a value for the missing path: