Merge "Fix SlotDiffRenderer documentation"
[lhc/web/wiklou.git] / includes / libs / ParamValidator / TypeDef / FloatDef.php
1 <?php
2
3 namespace Wikimedia\ParamValidator\TypeDef;
4
5 use Wikimedia\ParamValidator\TypeDef;
6 use Wikimedia\ParamValidator\ValidationException;
7
8 /**
9 * Type definition for a floating-point type
10 *
11 * A valid representation consists of:
12 * - an optional sign (`+` or `-`)
13 * - a decimal number, using `.` as the decimal separator and no grouping
14 * - an optional E-notation suffix: the letter 'e' or 'E', an optional
15 * sign, and an integer
16 *
17 * Thus, for example, "12", "-.4", "6.022e23", or "+1.7e-10".
18 *
19 * The result from validate() is a PHP float.
20 *
21 * ValidationException codes:
22 * - 'badfloat': The value was invalid. No data.
23 * - 'notfinite': The value was in a valid format, but conversion resulted in
24 * infinity or NAN.
25 *
26 * @since 1.34
27 */
28 class FloatDef extends TypeDef {
29
30 public function validate( $name, $value, array $settings, array $options ) {
31 // Use a regex so as to avoid any potential oddness PHP's default conversion might allow.
32 if ( !preg_match( '/^[+-]?(?:\d*\.)?\d+(?:[eE][+-]?\d+)?$/D', $value ) ) {
33 throw new ValidationException( $name, $value, $settings, 'badfloat', [] );
34 }
35
36 $ret = (float)$value;
37 if ( !is_finite( $ret ) ) {
38 throw new ValidationException( $name, $value, $settings, 'notfinite', [] );
39 }
40
41 return $ret;
42 }
43
44 /**
45 * Attempt to fix locale weirdness
46 *
47 * We don't have any usable number formatting function that's not locale-aware,
48 * and `setlocale()` isn't safe in multithreaded environments. Sigh.
49 *
50 * @param string $value Value to fix
51 * @return string
52 */
53 private function fixLocaleWeirdness( $value ) {
54 $localeData = localeconv();
55 if ( $localeData['decimal_point'] !== '.' ) {
56 $value = strtr( $value, [
57 $localeData['decimal_point'] => '.',
58 // PHP's number formatting currently uses only the first byte from 'decimal_point'.
59 // See upstream bug https://bugs.php.net/bug.php?id=78113
60 $localeData['decimal_point'][0] => '.',
61 ] );
62 }
63 return $value;
64 }
65
66 public function stringifyValue( $name, $value, array $settings, array $options ) {
67 // Ensure sufficient precision for round-tripping. PHP_FLOAT_DIG was added in PHP 7.2.
68 $digits = defined( 'PHP_FLOAT_DIG' ) ? PHP_FLOAT_DIG : 15;
69 return $this->fixLocaleWeirdness( sprintf( "%.{$digits}g", $value ) );
70 }
71
72 }