@@ -3,20 +3,20 @@ |
||
| 3 | 3 | #[Attribute(Attribute::TARGET_CLASS)] |
| 4 | 4 | final class Attribute |
| 5 | 5 | { |
| 6 | - public const TARGET_CLASS = 1; |
|
| 7 | - public const TARGET_FUNCTION = 2; |
|
| 8 | - public const TARGET_METHOD = 4; |
|
| 9 | - public const TARGET_PROPERTY = 8; |
|
| 10 | - public const TARGET_CLASS_CONSTANT = 16; |
|
| 11 | - public const TARGET_PARAMETER = 32; |
|
| 12 | - public const TARGET_ALL = 63; |
|
| 13 | - public const IS_REPEATABLE = 64; |
|
| 6 | + public const TARGET_CLASS = 1; |
|
| 7 | + public const TARGET_FUNCTION = 2; |
|
| 8 | + public const TARGET_METHOD = 4; |
|
| 9 | + public const TARGET_PROPERTY = 8; |
|
| 10 | + public const TARGET_CLASS_CONSTANT = 16; |
|
| 11 | + public const TARGET_PARAMETER = 32; |
|
| 12 | + public const TARGET_ALL = 63; |
|
| 13 | + public const IS_REPEATABLE = 64; |
|
| 14 | 14 | |
| 15 | - /** @var int */ |
|
| 16 | - public $flags; |
|
| 15 | + /** @var int */ |
|
| 16 | + public $flags; |
|
| 17 | 17 | |
| 18 | - public function __construct(int $flags = self::TARGET_ALL) |
|
| 19 | - { |
|
| 20 | - $this->flags = $flags; |
|
| 21 | - } |
|
| 18 | + public function __construct(int $flags = self::TARGET_ALL) |
|
| 19 | + { |
|
| 20 | + $this->flags = $flags; |
|
| 21 | + } |
|
| 22 | 22 | } |
@@ -12,20 +12,20 @@ |
||
| 12 | 12 | use Symfony\Polyfill\Php73 as p; |
| 13 | 13 | |
| 14 | 14 | if (\PHP_VERSION_ID >= 70300) { |
| 15 | - return; |
|
| 15 | + return; |
|
| 16 | 16 | } |
| 17 | 17 | |
| 18 | 18 | if (!function_exists('is_countable')) { |
| 19 | - function is_countable($value) { return is_array($value) || $value instanceof Countable || $value instanceof ResourceBundle || $value instanceof SimpleXmlElement; } |
|
| 19 | + function is_countable($value) { return is_array($value) || $value instanceof Countable || $value instanceof ResourceBundle || $value instanceof SimpleXmlElement; } |
|
| 20 | 20 | } |
| 21 | 21 | if (!function_exists('hrtime')) { |
| 22 | - require_once __DIR__.'/Php73.php'; |
|
| 23 | - p\Php73::$startAt = (int) microtime(true); |
|
| 24 | - function hrtime($as_number = false) { return p\Php73::hrtime($as_number); } |
|
| 22 | + require_once __DIR__.'/Php73.php'; |
|
| 23 | + p\Php73::$startAt = (int) microtime(true); |
|
| 24 | + function hrtime($as_number = false) { return p\Php73::hrtime($as_number); } |
|
| 25 | 25 | } |
| 26 | 26 | if (!function_exists('array_key_first')) { |
| 27 | - function array_key_first(array $array) { foreach ($array as $key => $value) { return $key; } } |
|
| 27 | + function array_key_first(array $array) { foreach ($array as $key => $value) { return $key; } } |
|
| 28 | 28 | } |
| 29 | 29 | if (!function_exists('array_key_last')) { |
| 30 | - function array_key_last(array $array) { return key(array_slice($array, -1, 1, true)); } |
|
| 30 | + function array_key_last(array $array) { return key(array_slice($array, -1, 1, true)); } |
|
| 31 | 31 | } |
@@ -19,25 +19,25 @@ |
||
| 19 | 19 | */ |
| 20 | 20 | final class Php73 |
| 21 | 21 | { |
| 22 | - public static $startAt = 1533462603; |
|
| 22 | + public static $startAt = 1533462603; |
|
| 23 | 23 | |
| 24 | - /** |
|
| 25 | - * @param bool $asNum |
|
| 26 | - * |
|
| 27 | - * @return array|float|int |
|
| 28 | - */ |
|
| 29 | - public static function hrtime($asNum = false) |
|
| 30 | - { |
|
| 31 | - $ns = microtime(false); |
|
| 32 | - $s = substr($ns, 11) - self::$startAt; |
|
| 33 | - $ns = 1E9 * (float) $ns; |
|
| 24 | + /** |
|
| 25 | + * @param bool $asNum |
|
| 26 | + * |
|
| 27 | + * @return array|float|int |
|
| 28 | + */ |
|
| 29 | + public static function hrtime($asNum = false) |
|
| 30 | + { |
|
| 31 | + $ns = microtime(false); |
|
| 32 | + $s = substr($ns, 11) - self::$startAt; |
|
| 33 | + $ns = 1E9 * (float) $ns; |
|
| 34 | 34 | |
| 35 | - if ($asNum) { |
|
| 36 | - $ns += $s * 1E9; |
|
| 35 | + if ($asNum) { |
|
| 36 | + $ns += $s * 1E9; |
|
| 37 | 37 | |
| 38 | - return \PHP_INT_SIZE === 4 ? $ns : (int) $ns; |
|
| 39 | - } |
|
| 38 | + return \PHP_INT_SIZE === 4 ? $ns : (int) $ns; |
|
| 39 | + } |
|
| 40 | 40 | |
| 41 | - return [$s, (int) $ns]; |
|
| 42 | - } |
|
| 41 | + return [$s, (int) $ns]; |
|
| 42 | + } |
|
| 43 | 43 | } |
@@ -12,47 +12,47 @@ |
||
| 12 | 12 | use Symfony\Polyfill\Intl\Grapheme as p; |
| 13 | 13 | |
| 14 | 14 | if (extension_loaded('intl')) { |
| 15 | - return; |
|
| 15 | + return; |
|
| 16 | 16 | } |
| 17 | 17 | |
| 18 | 18 | if (\PHP_VERSION_ID >= 80000) { |
| 19 | - return require __DIR__.'/bootstrap80.php'; |
|
| 19 | + return require __DIR__.'/bootstrap80.php'; |
|
| 20 | 20 | } |
| 21 | 21 | |
| 22 | 22 | if (!defined('GRAPHEME_EXTR_COUNT')) { |
| 23 | - define('GRAPHEME_EXTR_COUNT', 0); |
|
| 23 | + define('GRAPHEME_EXTR_COUNT', 0); |
|
| 24 | 24 | } |
| 25 | 25 | if (!defined('GRAPHEME_EXTR_MAXBYTES')) { |
| 26 | - define('GRAPHEME_EXTR_MAXBYTES', 1); |
|
| 26 | + define('GRAPHEME_EXTR_MAXBYTES', 1); |
|
| 27 | 27 | } |
| 28 | 28 | if (!defined('GRAPHEME_EXTR_MAXCHARS')) { |
| 29 | - define('GRAPHEME_EXTR_MAXCHARS', 2); |
|
| 29 | + define('GRAPHEME_EXTR_MAXCHARS', 2); |
|
| 30 | 30 | } |
| 31 | 31 | |
| 32 | 32 | if (!function_exists('grapheme_extract')) { |
| 33 | - function grapheme_extract($haystack, $size, $type = 0, $start = 0, &$next = 0) { return p\Grapheme::grapheme_extract($haystack, $size, $type, $start, $next); } |
|
| 33 | + function grapheme_extract($haystack, $size, $type = 0, $start = 0, &$next = 0) { return p\Grapheme::grapheme_extract($haystack, $size, $type, $start, $next); } |
|
| 34 | 34 | } |
| 35 | 35 | if (!function_exists('grapheme_stripos')) { |
| 36 | - function grapheme_stripos($haystack, $needle, $offset = 0) { return p\Grapheme::grapheme_stripos($haystack, $needle, $offset); } |
|
| 36 | + function grapheme_stripos($haystack, $needle, $offset = 0) { return p\Grapheme::grapheme_stripos($haystack, $needle, $offset); } |
|
| 37 | 37 | } |
| 38 | 38 | if (!function_exists('grapheme_stristr')) { |
| 39 | - function grapheme_stristr($haystack, $needle, $beforeNeedle = false) { return p\Grapheme::grapheme_stristr($haystack, $needle, $beforeNeedle); } |
|
| 39 | + function grapheme_stristr($haystack, $needle, $beforeNeedle = false) { return p\Grapheme::grapheme_stristr($haystack, $needle, $beforeNeedle); } |
|
| 40 | 40 | } |
| 41 | 41 | if (!function_exists('grapheme_strlen')) { |
| 42 | - function grapheme_strlen($input) { return p\Grapheme::grapheme_strlen($input); } |
|
| 42 | + function grapheme_strlen($input) { return p\Grapheme::grapheme_strlen($input); } |
|
| 43 | 43 | } |
| 44 | 44 | if (!function_exists('grapheme_strpos')) { |
| 45 | - function grapheme_strpos($haystack, $needle, $offset = 0) { return p\Grapheme::grapheme_strpos($haystack, $needle, $offset); } |
|
| 45 | + function grapheme_strpos($haystack, $needle, $offset = 0) { return p\Grapheme::grapheme_strpos($haystack, $needle, $offset); } |
|
| 46 | 46 | } |
| 47 | 47 | if (!function_exists('grapheme_strripos')) { |
| 48 | - function grapheme_strripos($haystack, $needle, $offset = 0) { return p\Grapheme::grapheme_strripos($haystack, $needle, $offset); } |
|
| 48 | + function grapheme_strripos($haystack, $needle, $offset = 0) { return p\Grapheme::grapheme_strripos($haystack, $needle, $offset); } |
|
| 49 | 49 | } |
| 50 | 50 | if (!function_exists('grapheme_strrpos')) { |
| 51 | - function grapheme_strrpos($haystack, $needle, $offset = 0) { return p\Grapheme::grapheme_strrpos($haystack, $needle, $offset); } |
|
| 51 | + function grapheme_strrpos($haystack, $needle, $offset = 0) { return p\Grapheme::grapheme_strrpos($haystack, $needle, $offset); } |
|
| 52 | 52 | } |
| 53 | 53 | if (!function_exists('grapheme_strstr')) { |
| 54 | - function grapheme_strstr($haystack, $needle, $beforeNeedle = false) { return p\Grapheme::grapheme_strstr($haystack, $needle, $beforeNeedle); } |
|
| 54 | + function grapheme_strstr($haystack, $needle, $beforeNeedle = false) { return p\Grapheme::grapheme_strstr($haystack, $needle, $beforeNeedle); } |
|
| 55 | 55 | } |
| 56 | 56 | if (!function_exists('grapheme_substr')) { |
| 57 | - function grapheme_substr($string, $offset, $length = null) { return p\Grapheme::grapheme_substr($string, $offset, $length); } |
|
| 57 | + function grapheme_substr($string, $offset, $length = null) { return p\Grapheme::grapheme_substr($string, $offset, $length); } |
|
| 58 | 58 | } |
@@ -33,215 +33,215 @@ |
||
| 33 | 33 | */ |
| 34 | 34 | final class Grapheme |
| 35 | 35 | { |
| 36 | - // (CRLF|([ZWNJ-ZWJ]|T+|L*(LV?V+|LV|LVT)T*|L+|[^Control])[Extend]*|[Control]) |
|
| 37 | - // This regular expression is a work around for http://bugs.exim.org/1279 |
|
| 38 | - public const GRAPHEME_CLUSTER_RX = '(?:\r\n|(?:[ -~\x{200C}\x{200D}]|[ᆨ-ᇹ]+|[ᄀ-ᅟ]*(?:[가개갸걔거게겨계고과괘괴교구궈궤귀규그긔기까깨꺄꺠꺼께껴꼐꼬꽈꽤꾀꾜꾸꿔꿰뀌뀨끄끠끼나내냐냬너네녀녜노놔놰뇌뇨누눠눼뉘뉴느늬니다대댜댸더데뎌뎨도돠돼되됴두둬뒈뒤듀드듸디따때땨떄떠떼뗘뗴또똬뙈뙤뚀뚜뚸뛔뛰뜌뜨띄띠라래랴럐러레려례로롸뢔뢰료루뤄뤠뤼류르릐리마매먀먜머메며몌모뫄뫠뫼묘무뭐뭬뮈뮤므믜미바배뱌뱨버베벼볘보봐봬뵈뵤부붜붸뷔뷰브븨비빠빼뺘뺴뻐뻬뼈뼤뽀뽜뽸뾔뾰뿌뿨쀄쀠쀼쁘쁴삐사새샤섀서세셔셰소솨쇄쇠쇼수숴쉐쉬슈스싀시싸쌔쌰썌써쎄쎠쎼쏘쏴쐐쐬쑈쑤쒀쒜쒸쓔쓰씌씨아애야얘어에여예오와왜외요우워웨위유으의이자재쟈쟤저제져졔조좌좨죄죠주줘줴쥐쥬즈즤지짜째쨔쨰쩌쩨쪄쪠쪼쫘쫴쬐쬬쭈쭤쮀쮜쮸쯔쯰찌차채챠챼처체쳐쳬초촤쵀최쵸추춰췌취츄츠츼치카캐캬컈커케켜켸코콰쾌쾨쿄쿠쿼퀘퀴큐크킈키타태탸턔터테텨톄토톼퇘퇴툐투퉈퉤튀튜트틔티파패퍄퍠퍼페펴폐포퐈퐤푀표푸풔풰퓌퓨프픠피하해햐햬허헤혀혜호화홰회효후훠훼휘휴흐희히]?[ᅠ-ᆢ]+|[가-힣])[ᆨ-ᇹ]*|[ᄀ-ᅟ]+|[^\p{Cc}\p{Cf}\p{Zl}\p{Zp}])[\p{Mn}\p{Me}\x{09BE}\x{09D7}\x{0B3E}\x{0B57}\x{0BBE}\x{0BD7}\x{0CC2}\x{0CD5}\x{0CD6}\x{0D3E}\x{0D57}\x{0DCF}\x{0DDF}\x{200C}\x{200D}\x{1D165}\x{1D16E}-\x{1D172}]*|[\p{Cc}\p{Cf}\p{Zl}\p{Zp}])'; |
|
| 39 | - |
|
| 40 | - private const CASE_FOLD = [ |
|
| 41 | - ['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"], |
|
| 42 | - ['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'], |
|
| 43 | - ]; |
|
| 44 | - |
|
| 45 | - public static function grapheme_extract($s, $size, $type = \GRAPHEME_EXTR_COUNT, $start = 0, &$next = 0) |
|
| 46 | - { |
|
| 47 | - if (0 > $start) { |
|
| 48 | - $start = \strlen($s) + $start; |
|
| 49 | - } |
|
| 50 | - |
|
| 51 | - if (!is_scalar($s)) { |
|
| 52 | - $hasError = false; |
|
| 53 | - set_error_handler(function () use (&$hasError) { $hasError = true; }); |
|
| 54 | - $next = substr($s, $start); |
|
| 55 | - restore_error_handler(); |
|
| 56 | - if ($hasError) { |
|
| 57 | - substr($s, $start); |
|
| 58 | - $s = ''; |
|
| 59 | - } else { |
|
| 60 | - $s = $next; |
|
| 61 | - } |
|
| 62 | - } else { |
|
| 63 | - $s = substr($s, $start); |
|
| 64 | - } |
|
| 65 | - $size = (int) $size; |
|
| 66 | - $type = (int) $type; |
|
| 67 | - $start = (int) $start; |
|
| 68 | - |
|
| 69 | - if (\GRAPHEME_EXTR_COUNT !== $type && \GRAPHEME_EXTR_MAXBYTES !== $type && \GRAPHEME_EXTR_MAXCHARS !== $type) { |
|
| 70 | - if (80000 > \PHP_VERSION_ID) { |
|
| 71 | - return false; |
|
| 72 | - } |
|
| 73 | - |
|
| 74 | - throw new \ValueError('grapheme_extract(): Argument #3 ($type) must be one of GRAPHEME_EXTR_COUNT, GRAPHEME_EXTR_MAXBYTES, or GRAPHEME_EXTR_MAXCHARS'); |
|
| 75 | - } |
|
| 76 | - |
|
| 77 | - if (!isset($s[0]) || 0 > $size || 0 > $start) { |
|
| 78 | - return false; |
|
| 79 | - } |
|
| 80 | - if (0 === $size) { |
|
| 81 | - return ''; |
|
| 82 | - } |
|
| 83 | - |
|
| 84 | - $next = $start; |
|
| 85 | - |
|
| 86 | - $s = preg_split('/('.SYMFONY_GRAPHEME_CLUSTER_RX.')/u', "\r\n".$s, $size + 1, \PREG_SPLIT_NO_EMPTY | \PREG_SPLIT_DELIM_CAPTURE); |
|
| 87 | - |
|
| 88 | - if (!isset($s[1])) { |
|
| 89 | - return false; |
|
| 90 | - } |
|
| 91 | - |
|
| 92 | - $i = 1; |
|
| 93 | - $ret = ''; |
|
| 94 | - |
|
| 95 | - do { |
|
| 96 | - if (\GRAPHEME_EXTR_COUNT === $type) { |
|
| 97 | - --$size; |
|
| 98 | - } elseif (\GRAPHEME_EXTR_MAXBYTES === $type) { |
|
| 99 | - $size -= \strlen($s[$i]); |
|
| 100 | - } else { |
|
| 101 | - $size -= iconv_strlen($s[$i], 'UTF-8//IGNORE'); |
|
| 102 | - } |
|
| 103 | - |
|
| 104 | - if ($size >= 0) { |
|
| 105 | - $ret .= $s[$i]; |
|
| 106 | - } |
|
| 107 | - } while (isset($s[++$i]) && $size > 0); |
|
| 108 | - |
|
| 109 | - $next += \strlen($ret); |
|
| 110 | - |
|
| 111 | - return $ret; |
|
| 112 | - } |
|
| 113 | - |
|
| 114 | - public static function grapheme_strlen($s) |
|
| 115 | - { |
|
| 116 | - preg_replace('/'.SYMFONY_GRAPHEME_CLUSTER_RX.'/u', '', $s, -1, $len); |
|
| 117 | - |
|
| 118 | - return 0 === $len && '' !== $s ? null : $len; |
|
| 119 | - } |
|
| 120 | - |
|
| 121 | - public static function grapheme_substr($s, $start, $len = null) |
|
| 122 | - { |
|
| 123 | - if (null === $len) { |
|
| 124 | - $len = 2147483647; |
|
| 125 | - } |
|
| 126 | - |
|
| 127 | - preg_match_all('/'.SYMFONY_GRAPHEME_CLUSTER_RX.'/u', $s, $s); |
|
| 128 | - |
|
| 129 | - $slen = \count($s[0]); |
|
| 130 | - $start = (int) $start; |
|
| 131 | - |
|
| 132 | - if (0 > $start) { |
|
| 133 | - $start += $slen; |
|
| 134 | - } |
|
| 135 | - if (0 > $start) { |
|
| 136 | - if (\PHP_VERSION_ID < 80000) { |
|
| 137 | - return false; |
|
| 138 | - } |
|
| 139 | - |
|
| 140 | - $start = 0; |
|
| 141 | - } |
|
| 142 | - if ($start >= $slen) { |
|
| 143 | - return \PHP_VERSION_ID >= 80000 ? '' : false; |
|
| 144 | - } |
|
| 145 | - |
|
| 146 | - $rem = $slen - $start; |
|
| 147 | - |
|
| 148 | - if (0 > $len) { |
|
| 149 | - $len += $rem; |
|
| 150 | - } |
|
| 151 | - if (0 === $len) { |
|
| 152 | - return ''; |
|
| 153 | - } |
|
| 154 | - if (0 > $len) { |
|
| 155 | - return \PHP_VERSION_ID >= 80000 ? '' : false; |
|
| 156 | - } |
|
| 157 | - if ($len > $rem) { |
|
| 158 | - $len = $rem; |
|
| 159 | - } |
|
| 160 | - |
|
| 161 | - return implode('', \array_slice($s[0], $start, $len)); |
|
| 162 | - } |
|
| 163 | - |
|
| 164 | - public static function grapheme_strpos($s, $needle, $offset = 0) |
|
| 165 | - { |
|
| 166 | - return self::grapheme_position($s, $needle, $offset, 0); |
|
| 167 | - } |
|
| 168 | - |
|
| 169 | - public static function grapheme_stripos($s, $needle, $offset = 0) |
|
| 170 | - { |
|
| 171 | - return self::grapheme_position($s, $needle, $offset, 1); |
|
| 172 | - } |
|
| 173 | - |
|
| 174 | - public static function grapheme_strrpos($s, $needle, $offset = 0) |
|
| 175 | - { |
|
| 176 | - return self::grapheme_position($s, $needle, $offset, 2); |
|
| 177 | - } |
|
| 178 | - |
|
| 179 | - public static function grapheme_strripos($s, $needle, $offset = 0) |
|
| 180 | - { |
|
| 181 | - return self::grapheme_position($s, $needle, $offset, 3); |
|
| 182 | - } |
|
| 183 | - |
|
| 184 | - public static function grapheme_stristr($s, $needle, $beforeNeedle = false) |
|
| 185 | - { |
|
| 186 | - return mb_stristr($s, $needle, $beforeNeedle, 'UTF-8'); |
|
| 187 | - } |
|
| 188 | - |
|
| 189 | - public static function grapheme_strstr($s, $needle, $beforeNeedle = false) |
|
| 190 | - { |
|
| 191 | - return mb_strstr($s, $needle, $beforeNeedle, 'UTF-8'); |
|
| 192 | - } |
|
| 193 | - |
|
| 194 | - private static function grapheme_position($s, $needle, $offset, $mode) |
|
| 195 | - { |
|
| 196 | - $needle = (string) $needle; |
|
| 197 | - if (80000 > \PHP_VERSION_ID && !preg_match('/./us', $needle)) { |
|
| 198 | - return false; |
|
| 199 | - } |
|
| 200 | - $s = (string) $s; |
|
| 201 | - if (!preg_match('/./us', $s)) { |
|
| 202 | - return false; |
|
| 203 | - } |
|
| 204 | - if ($offset > 0) { |
|
| 205 | - $s = self::grapheme_substr($s, $offset); |
|
| 206 | - } elseif ($offset < 0) { |
|
| 207 | - if (2 > $mode) { |
|
| 208 | - $offset += self::grapheme_strlen($s); |
|
| 209 | - $s = self::grapheme_substr($s, $offset); |
|
| 210 | - if (0 > $offset) { |
|
| 211 | - $offset = 0; |
|
| 212 | - } |
|
| 213 | - } elseif (0 > $offset += self::grapheme_strlen($needle)) { |
|
| 214 | - $s = self::grapheme_substr($s, 0, $offset); |
|
| 215 | - $offset = 0; |
|
| 216 | - } else { |
|
| 217 | - $offset = 0; |
|
| 218 | - } |
|
| 219 | - } |
|
| 220 | - |
|
| 221 | - // As UTF-8 is self-synchronizing, and we have ensured the strings are valid UTF-8, |
|
| 222 | - // we can use normal binary string functions here. For case-insensitive searches, |
|
| 223 | - // case fold the strings first. |
|
| 224 | - $caseInsensitive = $mode & 1; |
|
| 225 | - $reverse = $mode & 2; |
|
| 226 | - if ($caseInsensitive) { |
|
| 227 | - // Use the same case folding mode as mbstring does for mb_stripos(). |
|
| 228 | - // Stick to SIMPLE case folding to avoid changing the length of the string, which |
|
| 229 | - // might result in offsets being shifted. |
|
| 230 | - $mode = \defined('MB_CASE_FOLD_SIMPLE') ? \MB_CASE_FOLD_SIMPLE : \MB_CASE_LOWER; |
|
| 231 | - $s = mb_convert_case($s, $mode, 'UTF-8'); |
|
| 232 | - $needle = mb_convert_case($needle, $mode, 'UTF-8'); |
|
| 233 | - |
|
| 234 | - if (!\defined('MB_CASE_FOLD_SIMPLE')) { |
|
| 235 | - $s = str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $s); |
|
| 236 | - $needle = str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $needle); |
|
| 237 | - } |
|
| 238 | - } |
|
| 239 | - if ($reverse) { |
|
| 240 | - $needlePos = strrpos($s, $needle); |
|
| 241 | - } else { |
|
| 242 | - $needlePos = strpos($s, $needle); |
|
| 243 | - } |
|
| 244 | - |
|
| 245 | - return false !== $needlePos ? self::grapheme_strlen(substr($s, 0, $needlePos)) + $offset : false; |
|
| 246 | - } |
|
| 36 | + // (CRLF|([ZWNJ-ZWJ]|T+|L*(LV?V+|LV|LVT)T*|L+|[^Control])[Extend]*|[Control]) |
|
| 37 | + // This regular expression is a work around for http://bugs.exim.org/1279 |
|
| 38 | + public const GRAPHEME_CLUSTER_RX = '(?:\r\n|(?:[ -~\x{200C}\x{200D}]|[ᆨ-ᇹ]+|[ᄀ-ᅟ]*(?:[가개갸걔거게겨계고과괘괴교구궈궤귀규그긔기까깨꺄꺠꺼께껴꼐꼬꽈꽤꾀꾜꾸꿔꿰뀌뀨끄끠끼나내냐냬너네녀녜노놔놰뇌뇨누눠눼뉘뉴느늬니다대댜댸더데뎌뎨도돠돼되됴두둬뒈뒤듀드듸디따때땨떄떠떼뗘뗴또똬뙈뙤뚀뚜뚸뛔뛰뜌뜨띄띠라래랴럐러레려례로롸뢔뢰료루뤄뤠뤼류르릐리마매먀먜머메며몌모뫄뫠뫼묘무뭐뭬뮈뮤므믜미바배뱌뱨버베벼볘보봐봬뵈뵤부붜붸뷔뷰브븨비빠빼뺘뺴뻐뻬뼈뼤뽀뽜뽸뾔뾰뿌뿨쀄쀠쀼쁘쁴삐사새샤섀서세셔셰소솨쇄쇠쇼수숴쉐쉬슈스싀시싸쌔쌰썌써쎄쎠쎼쏘쏴쐐쐬쑈쑤쒀쒜쒸쓔쓰씌씨아애야얘어에여예오와왜외요우워웨위유으의이자재쟈쟤저제져졔조좌좨죄죠주줘줴쥐쥬즈즤지짜째쨔쨰쩌쩨쪄쪠쪼쫘쫴쬐쬬쭈쭤쮀쮜쮸쯔쯰찌차채챠챼처체쳐쳬초촤쵀최쵸추춰췌취츄츠츼치카캐캬컈커케켜켸코콰쾌쾨쿄쿠쿼퀘퀴큐크킈키타태탸턔터테텨톄토톼퇘퇴툐투퉈퉤튀튜트틔티파패퍄퍠퍼페펴폐포퐈퐤푀표푸풔풰퓌퓨프픠피하해햐햬허헤혀혜호화홰회효후훠훼휘휴흐희히]?[ᅠ-ᆢ]+|[가-힣])[ᆨ-ᇹ]*|[ᄀ-ᅟ]+|[^\p{Cc}\p{Cf}\p{Zl}\p{Zp}])[\p{Mn}\p{Me}\x{09BE}\x{09D7}\x{0B3E}\x{0B57}\x{0BBE}\x{0BD7}\x{0CC2}\x{0CD5}\x{0CD6}\x{0D3E}\x{0D57}\x{0DCF}\x{0DDF}\x{200C}\x{200D}\x{1D165}\x{1D16E}-\x{1D172}]*|[\p{Cc}\p{Cf}\p{Zl}\p{Zp}])'; |
|
| 39 | + |
|
| 40 | + private const CASE_FOLD = [ |
|
| 41 | + ['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"], |
|
| 42 | + ['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'], |
|
| 43 | + ]; |
|
| 44 | + |
|
| 45 | + public static function grapheme_extract($s, $size, $type = \GRAPHEME_EXTR_COUNT, $start = 0, &$next = 0) |
|
| 46 | + { |
|
| 47 | + if (0 > $start) { |
|
| 48 | + $start = \strlen($s) + $start; |
|
| 49 | + } |
|
| 50 | + |
|
| 51 | + if (!is_scalar($s)) { |
|
| 52 | + $hasError = false; |
|
| 53 | + set_error_handler(function () use (&$hasError) { $hasError = true; }); |
|
| 54 | + $next = substr($s, $start); |
|
| 55 | + restore_error_handler(); |
|
| 56 | + if ($hasError) { |
|
| 57 | + substr($s, $start); |
|
| 58 | + $s = ''; |
|
| 59 | + } else { |
|
| 60 | + $s = $next; |
|
| 61 | + } |
|
| 62 | + } else { |
|
| 63 | + $s = substr($s, $start); |
|
| 64 | + } |
|
| 65 | + $size = (int) $size; |
|
| 66 | + $type = (int) $type; |
|
| 67 | + $start = (int) $start; |
|
| 68 | + |
|
| 69 | + if (\GRAPHEME_EXTR_COUNT !== $type && \GRAPHEME_EXTR_MAXBYTES !== $type && \GRAPHEME_EXTR_MAXCHARS !== $type) { |
|
| 70 | + if (80000 > \PHP_VERSION_ID) { |
|
| 71 | + return false; |
|
| 72 | + } |
|
| 73 | + |
|
| 74 | + throw new \ValueError('grapheme_extract(): Argument #3 ($type) must be one of GRAPHEME_EXTR_COUNT, GRAPHEME_EXTR_MAXBYTES, or GRAPHEME_EXTR_MAXCHARS'); |
|
| 75 | + } |
|
| 76 | + |
|
| 77 | + if (!isset($s[0]) || 0 > $size || 0 > $start) { |
|
| 78 | + return false; |
|
| 79 | + } |
|
| 80 | + if (0 === $size) { |
|
| 81 | + return ''; |
|
| 82 | + } |
|
| 83 | + |
|
| 84 | + $next = $start; |
|
| 85 | + |
|
| 86 | + $s = preg_split('/('.SYMFONY_GRAPHEME_CLUSTER_RX.')/u', "\r\n".$s, $size + 1, \PREG_SPLIT_NO_EMPTY | \PREG_SPLIT_DELIM_CAPTURE); |
|
| 87 | + |
|
| 88 | + if (!isset($s[1])) { |
|
| 89 | + return false; |
|
| 90 | + } |
|
| 91 | + |
|
| 92 | + $i = 1; |
|
| 93 | + $ret = ''; |
|
| 94 | + |
|
| 95 | + do { |
|
| 96 | + if (\GRAPHEME_EXTR_COUNT === $type) { |
|
| 97 | + --$size; |
|
| 98 | + } elseif (\GRAPHEME_EXTR_MAXBYTES === $type) { |
|
| 99 | + $size -= \strlen($s[$i]); |
|
| 100 | + } else { |
|
| 101 | + $size -= iconv_strlen($s[$i], 'UTF-8//IGNORE'); |
|
| 102 | + } |
|
| 103 | + |
|
| 104 | + if ($size >= 0) { |
|
| 105 | + $ret .= $s[$i]; |
|
| 106 | + } |
|
| 107 | + } while (isset($s[++$i]) && $size > 0); |
|
| 108 | + |
|
| 109 | + $next += \strlen($ret); |
|
| 110 | + |
|
| 111 | + return $ret; |
|
| 112 | + } |
|
| 113 | + |
|
| 114 | + public static function grapheme_strlen($s) |
|
| 115 | + { |
|
| 116 | + preg_replace('/'.SYMFONY_GRAPHEME_CLUSTER_RX.'/u', '', $s, -1, $len); |
|
| 117 | + |
|
| 118 | + return 0 === $len && '' !== $s ? null : $len; |
|
| 119 | + } |
|
| 120 | + |
|
| 121 | + public static function grapheme_substr($s, $start, $len = null) |
|
| 122 | + { |
|
| 123 | + if (null === $len) { |
|
| 124 | + $len = 2147483647; |
|
| 125 | + } |
|
| 126 | + |
|
| 127 | + preg_match_all('/'.SYMFONY_GRAPHEME_CLUSTER_RX.'/u', $s, $s); |
|
| 128 | + |
|
| 129 | + $slen = \count($s[0]); |
|
| 130 | + $start = (int) $start; |
|
| 131 | + |
|
| 132 | + if (0 > $start) { |
|
| 133 | + $start += $slen; |
|
| 134 | + } |
|
| 135 | + if (0 > $start) { |
|
| 136 | + if (\PHP_VERSION_ID < 80000) { |
|
| 137 | + return false; |
|
| 138 | + } |
|
| 139 | + |
|
| 140 | + $start = 0; |
|
| 141 | + } |
|
| 142 | + if ($start >= $slen) { |
|
| 143 | + return \PHP_VERSION_ID >= 80000 ? '' : false; |
|
| 144 | + } |
|
| 145 | + |
|
| 146 | + $rem = $slen - $start; |
|
| 147 | + |
|
| 148 | + if (0 > $len) { |
|
| 149 | + $len += $rem; |
|
| 150 | + } |
|
| 151 | + if (0 === $len) { |
|
| 152 | + return ''; |
|
| 153 | + } |
|
| 154 | + if (0 > $len) { |
|
| 155 | + return \PHP_VERSION_ID >= 80000 ? '' : false; |
|
| 156 | + } |
|
| 157 | + if ($len > $rem) { |
|
| 158 | + $len = $rem; |
|
| 159 | + } |
|
| 160 | + |
|
| 161 | + return implode('', \array_slice($s[0], $start, $len)); |
|
| 162 | + } |
|
| 163 | + |
|
| 164 | + public static function grapheme_strpos($s, $needle, $offset = 0) |
|
| 165 | + { |
|
| 166 | + return self::grapheme_position($s, $needle, $offset, 0); |
|
| 167 | + } |
|
| 168 | + |
|
| 169 | + public static function grapheme_stripos($s, $needle, $offset = 0) |
|
| 170 | + { |
|
| 171 | + return self::grapheme_position($s, $needle, $offset, 1); |
|
| 172 | + } |
|
| 173 | + |
|
| 174 | + public static function grapheme_strrpos($s, $needle, $offset = 0) |
|
| 175 | + { |
|
| 176 | + return self::grapheme_position($s, $needle, $offset, 2); |
|
| 177 | + } |
|
| 178 | + |
|
| 179 | + public static function grapheme_strripos($s, $needle, $offset = 0) |
|
| 180 | + { |
|
| 181 | + return self::grapheme_position($s, $needle, $offset, 3); |
|
| 182 | + } |
|
| 183 | + |
|
| 184 | + public static function grapheme_stristr($s, $needle, $beforeNeedle = false) |
|
| 185 | + { |
|
| 186 | + return mb_stristr($s, $needle, $beforeNeedle, 'UTF-8'); |
|
| 187 | + } |
|
| 188 | + |
|
| 189 | + public static function grapheme_strstr($s, $needle, $beforeNeedle = false) |
|
| 190 | + { |
|
| 191 | + return mb_strstr($s, $needle, $beforeNeedle, 'UTF-8'); |
|
| 192 | + } |
|
| 193 | + |
|
| 194 | + private static function grapheme_position($s, $needle, $offset, $mode) |
|
| 195 | + { |
|
| 196 | + $needle = (string) $needle; |
|
| 197 | + if (80000 > \PHP_VERSION_ID && !preg_match('/./us', $needle)) { |
|
| 198 | + return false; |
|
| 199 | + } |
|
| 200 | + $s = (string) $s; |
|
| 201 | + if (!preg_match('/./us', $s)) { |
|
| 202 | + return false; |
|
| 203 | + } |
|
| 204 | + if ($offset > 0) { |
|
| 205 | + $s = self::grapheme_substr($s, $offset); |
|
| 206 | + } elseif ($offset < 0) { |
|
| 207 | + if (2 > $mode) { |
|
| 208 | + $offset += self::grapheme_strlen($s); |
|
| 209 | + $s = self::grapheme_substr($s, $offset); |
|
| 210 | + if (0 > $offset) { |
|
| 211 | + $offset = 0; |
|
| 212 | + } |
|
| 213 | + } elseif (0 > $offset += self::grapheme_strlen($needle)) { |
|
| 214 | + $s = self::grapheme_substr($s, 0, $offset); |
|
| 215 | + $offset = 0; |
|
| 216 | + } else { |
|
| 217 | + $offset = 0; |
|
| 218 | + } |
|
| 219 | + } |
|
| 220 | + |
|
| 221 | + // As UTF-8 is self-synchronizing, and we have ensured the strings are valid UTF-8, |
|
| 222 | + // we can use normal binary string functions here. For case-insensitive searches, |
|
| 223 | + // case fold the strings first. |
|
| 224 | + $caseInsensitive = $mode & 1; |
|
| 225 | + $reverse = $mode & 2; |
|
| 226 | + if ($caseInsensitive) { |
|
| 227 | + // Use the same case folding mode as mbstring does for mb_stripos(). |
|
| 228 | + // Stick to SIMPLE case folding to avoid changing the length of the string, which |
|
| 229 | + // might result in offsets being shifted. |
|
| 230 | + $mode = \defined('MB_CASE_FOLD_SIMPLE') ? \MB_CASE_FOLD_SIMPLE : \MB_CASE_LOWER; |
|
| 231 | + $s = mb_convert_case($s, $mode, 'UTF-8'); |
|
| 232 | + $needle = mb_convert_case($needle, $mode, 'UTF-8'); |
|
| 233 | + |
|
| 234 | + if (!\defined('MB_CASE_FOLD_SIMPLE')) { |
|
| 235 | + $s = str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $s); |
|
| 236 | + $needle = str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $needle); |
|
| 237 | + } |
|
| 238 | + } |
|
| 239 | + if ($reverse) { |
|
| 240 | + $needlePos = strrpos($s, $needle); |
|
| 241 | + } else { |
|
| 242 | + $needlePos = strpos($s, $needle); |
|
| 243 | + } |
|
| 244 | + |
|
| 245 | + return false !== $needlePos ? self::grapheme_strlen(substr($s, 0, $needlePos)) + $offset : false; |
|
| 246 | + } |
|
| 247 | 247 | } |
@@ -12,39 +12,39 @@ |
||
| 12 | 12 | use Symfony\Polyfill\Intl\Grapheme as p; |
| 13 | 13 | |
| 14 | 14 | if (!defined('GRAPHEME_EXTR_COUNT')) { |
| 15 | - define('GRAPHEME_EXTR_COUNT', 0); |
|
| 15 | + define('GRAPHEME_EXTR_COUNT', 0); |
|
| 16 | 16 | } |
| 17 | 17 | if (!defined('GRAPHEME_EXTR_MAXBYTES')) { |
| 18 | - define('GRAPHEME_EXTR_MAXBYTES', 1); |
|
| 18 | + define('GRAPHEME_EXTR_MAXBYTES', 1); |
|
| 19 | 19 | } |
| 20 | 20 | if (!defined('GRAPHEME_EXTR_MAXCHARS')) { |
| 21 | - define('GRAPHEME_EXTR_MAXCHARS', 2); |
|
| 21 | + define('GRAPHEME_EXTR_MAXCHARS', 2); |
|
| 22 | 22 | } |
| 23 | 23 | |
| 24 | 24 | if (!function_exists('grapheme_extract')) { |
| 25 | - function grapheme_extract(?string $haystack, ?int $size, ?int $type = GRAPHEME_EXTR_COUNT, ?int $offset = 0, &$next = null): string|false { return p\Grapheme::grapheme_extract((string) $haystack, (int) $size, (int) $type, (int) $offset, $next); } |
|
| 25 | + function grapheme_extract(?string $haystack, ?int $size, ?int $type = GRAPHEME_EXTR_COUNT, ?int $offset = 0, &$next = null): string|false { return p\Grapheme::grapheme_extract((string) $haystack, (int) $size, (int) $type, (int) $offset, $next); } |
|
| 26 | 26 | } |
| 27 | 27 | if (!function_exists('grapheme_stripos')) { |
| 28 | - function grapheme_stripos(?string $haystack, ?string $needle, ?int $offset = 0): int|false { return p\Grapheme::grapheme_stripos((string) $haystack, (string) $needle, (int) $offset); } |
|
| 28 | + function grapheme_stripos(?string $haystack, ?string $needle, ?int $offset = 0): int|false { return p\Grapheme::grapheme_stripos((string) $haystack, (string) $needle, (int) $offset); } |
|
| 29 | 29 | } |
| 30 | 30 | if (!function_exists('grapheme_stristr')) { |
| 31 | - function grapheme_stristr(?string $haystack, ?string $needle, ?bool $beforeNeedle = false): string|false { return p\Grapheme::grapheme_stristr((string) $haystack, (string) $needle, (bool) $beforeNeedle); } |
|
| 31 | + function grapheme_stristr(?string $haystack, ?string $needle, ?bool $beforeNeedle = false): string|false { return p\Grapheme::grapheme_stristr((string) $haystack, (string) $needle, (bool) $beforeNeedle); } |
|
| 32 | 32 | } |
| 33 | 33 | if (!function_exists('grapheme_strlen')) { |
| 34 | - function grapheme_strlen(?string $string): int|false|null { return p\Grapheme::grapheme_strlen((string) $string); } |
|
| 34 | + function grapheme_strlen(?string $string): int|false|null { return p\Grapheme::grapheme_strlen((string) $string); } |
|
| 35 | 35 | } |
| 36 | 36 | if (!function_exists('grapheme_strpos')) { |
| 37 | - function grapheme_strpos(?string $haystack, ?string $needle, ?int $offset = 0): int|false { return p\Grapheme::grapheme_strpos((string) $haystack, (string) $needle, (int) $offset); } |
|
| 37 | + function grapheme_strpos(?string $haystack, ?string $needle, ?int $offset = 0): int|false { return p\Grapheme::grapheme_strpos((string) $haystack, (string) $needle, (int) $offset); } |
|
| 38 | 38 | } |
| 39 | 39 | if (!function_exists('grapheme_strripos')) { |
| 40 | - function grapheme_strripos(?string $haystack, ?string $needle, ?int $offset = 0): int|false { return p\Grapheme::grapheme_strripos((string) $haystack, (string) $needle, (int) $offset); } |
|
| 40 | + function grapheme_strripos(?string $haystack, ?string $needle, ?int $offset = 0): int|false { return p\Grapheme::grapheme_strripos((string) $haystack, (string) $needle, (int) $offset); } |
|
| 41 | 41 | } |
| 42 | 42 | if (!function_exists('grapheme_strrpos')) { |
| 43 | - function grapheme_strrpos(?string $haystack, ?string $needle, ?int $offset = 0): int|false { return p\Grapheme::grapheme_strrpos((string) $haystack, (string) $needle, (int) $offset); } |
|
| 43 | + function grapheme_strrpos(?string $haystack, ?string $needle, ?int $offset = 0): int|false { return p\Grapheme::grapheme_strrpos((string) $haystack, (string) $needle, (int) $offset); } |
|
| 44 | 44 | } |
| 45 | 45 | if (!function_exists('grapheme_strstr')) { |
| 46 | - function grapheme_strstr(?string $haystack, ?string $needle, ?bool $beforeNeedle = false): string|false { return p\Grapheme::grapheme_strstr((string) $haystack, (string) $needle, (bool) $beforeNeedle); } |
|
| 46 | + function grapheme_strstr(?string $haystack, ?string $needle, ?bool $beforeNeedle = false): string|false { return p\Grapheme::grapheme_strstr((string) $haystack, (string) $needle, (bool) $beforeNeedle); } |
|
| 47 | 47 | } |
| 48 | 48 | if (!function_exists('grapheme_substr')) { |
| 49 | - function grapheme_substr(?string $string, ?int $offset, ?int $length = null): string|false { return p\Grapheme::grapheme_substr((string) $string, (int) $offset, $length); } |
|
| 49 | + function grapheme_substr(?string $string, ?int $offset, ?int $length = null): string|false { return p\Grapheme::grapheme_substr((string) $string, (int) $offset, $length); } |
|
| 50 | 50 | } |
@@ -28,26 +28,26 @@ |
||
| 28 | 28 | */ |
| 29 | 29 | interface ServiceSubscriberInterface |
| 30 | 30 | { |
| 31 | - /** |
|
| 32 | - * Returns an array of service types required by such instances, optionally keyed by the service names used internally. |
|
| 33 | - * |
|
| 34 | - * For mandatory dependencies: |
|
| 35 | - * |
|
| 36 | - * * ['logger' => 'Psr\Log\LoggerInterface'] means the objects use the "logger" name |
|
| 37 | - * internally to fetch a service which must implement Psr\Log\LoggerInterface. |
|
| 38 | - * * ['loggers' => 'Psr\Log\LoggerInterface[]'] means the objects use the "loggers" name |
|
| 39 | - * internally to fetch an iterable of Psr\Log\LoggerInterface instances. |
|
| 40 | - * * ['Psr\Log\LoggerInterface'] is a shortcut for |
|
| 41 | - * * ['Psr\Log\LoggerInterface' => 'Psr\Log\LoggerInterface'] |
|
| 42 | - * |
|
| 43 | - * otherwise: |
|
| 44 | - * |
|
| 45 | - * * ['logger' => '?Psr\Log\LoggerInterface'] denotes an optional dependency |
|
| 46 | - * * ['loggers' => '?Psr\Log\LoggerInterface[]'] denotes an optional iterable dependency |
|
| 47 | - * * ['?Psr\Log\LoggerInterface'] is a shortcut for |
|
| 48 | - * * ['Psr\Log\LoggerInterface' => '?Psr\Log\LoggerInterface'] |
|
| 49 | - * |
|
| 50 | - * @return string[] The required service types, optionally keyed by service names |
|
| 51 | - */ |
|
| 52 | - public static function getSubscribedServices(); |
|
| 31 | + /** |
|
| 32 | + * Returns an array of service types required by such instances, optionally keyed by the service names used internally. |
|
| 33 | + * |
|
| 34 | + * For mandatory dependencies: |
|
| 35 | + * |
|
| 36 | + * * ['logger' => 'Psr\Log\LoggerInterface'] means the objects use the "logger" name |
|
| 37 | + * internally to fetch a service which must implement Psr\Log\LoggerInterface. |
|
| 38 | + * * ['loggers' => 'Psr\Log\LoggerInterface[]'] means the objects use the "loggers" name |
|
| 39 | + * internally to fetch an iterable of Psr\Log\LoggerInterface instances. |
|
| 40 | + * * ['Psr\Log\LoggerInterface'] is a shortcut for |
|
| 41 | + * * ['Psr\Log\LoggerInterface' => 'Psr\Log\LoggerInterface'] |
|
| 42 | + * |
|
| 43 | + * otherwise: |
|
| 44 | + * |
|
| 45 | + * * ['logger' => '?Psr\Log\LoggerInterface'] denotes an optional dependency |
|
| 46 | + * * ['loggers' => '?Psr\Log\LoggerInterface[]'] denotes an optional iterable dependency |
|
| 47 | + * * ['?Psr\Log\LoggerInterface'] is a shortcut for |
|
| 48 | + * * ['Psr\Log\LoggerInterface' => '?Psr\Log\LoggerInterface'] |
|
| 49 | + * |
|
| 50 | + * @return string[] The required service types, optionally keyed by service names |
|
| 51 | + */ |
|
| 52 | + public static function getSubscribedServices(); |
|
| 53 | 53 | } |
@@ -21,16 +21,16 @@ |
||
| 21 | 21 | */ |
| 22 | 22 | interface ServiceProviderInterface extends ContainerInterface |
| 23 | 23 | { |
| 24 | - /** |
|
| 25 | - * Returns an associative array of service types keyed by the identifiers provided by the current container. |
|
| 26 | - * |
|
| 27 | - * Examples: |
|
| 28 | - * |
|
| 29 | - * * ['logger' => 'Psr\Log\LoggerInterface'] means the object provides a service named "logger" that implements Psr\Log\LoggerInterface |
|
| 30 | - * * ['foo' => '?'] means the container provides service name "foo" of unspecified type |
|
| 31 | - * * ['bar' => '?Bar\Baz'] means the container provides a service "bar" of type Bar\Baz|null |
|
| 32 | - * |
|
| 33 | - * @return string[] The provided service types, keyed by service names |
|
| 34 | - */ |
|
| 35 | - public function getProvidedServices(): array; |
|
| 24 | + /** |
|
| 25 | + * Returns an associative array of service types keyed by the identifiers provided by the current container. |
|
| 26 | + * |
|
| 27 | + * Examples: |
|
| 28 | + * |
|
| 29 | + * * ['logger' => 'Psr\Log\LoggerInterface'] means the object provides a service named "logger" that implements Psr\Log\LoggerInterface |
|
| 30 | + * * ['foo' => '?'] means the container provides service name "foo" of unspecified type |
|
| 31 | + * * ['bar' => '?Bar\Baz'] means the container provides a service "bar" of type Bar\Baz|null |
|
| 32 | + * |
|
| 33 | + * @return string[] The provided service types, keyed by service names |
|
| 34 | + */ |
|
| 35 | + public function getProvidedServices(): array; |
|
| 36 | 36 | } |
@@ -26,103 +26,103 @@ |
||
| 26 | 26 | */ |
| 27 | 27 | trait ServiceLocatorTrait |
| 28 | 28 | { |
| 29 | - private $factories; |
|
| 30 | - private $loading = []; |
|
| 31 | - private $providedTypes; |
|
| 32 | - |
|
| 33 | - /** |
|
| 34 | - * @param callable[] $factories |
|
| 35 | - */ |
|
| 36 | - public function __construct(array $factories) |
|
| 37 | - { |
|
| 38 | - $this->factories = $factories; |
|
| 39 | - } |
|
| 40 | - |
|
| 41 | - /** |
|
| 42 | - * {@inheritdoc} |
|
| 43 | - * |
|
| 44 | - * @return bool |
|
| 45 | - */ |
|
| 46 | - public function has(string $id) |
|
| 47 | - { |
|
| 48 | - return isset($this->factories[$id]); |
|
| 49 | - } |
|
| 50 | - |
|
| 51 | - /** |
|
| 52 | - * {@inheritdoc} |
|
| 53 | - * |
|
| 54 | - * @return mixed |
|
| 55 | - */ |
|
| 56 | - public function get(string $id) |
|
| 57 | - { |
|
| 58 | - if (!isset($this->factories[$id])) { |
|
| 59 | - throw $this->createNotFoundException($id); |
|
| 60 | - } |
|
| 61 | - |
|
| 62 | - if (isset($this->loading[$id])) { |
|
| 63 | - $ids = array_values($this->loading); |
|
| 64 | - $ids = \array_slice($this->loading, array_search($id, $ids)); |
|
| 65 | - $ids[] = $id; |
|
| 66 | - |
|
| 67 | - throw $this->createCircularReferenceException($id, $ids); |
|
| 68 | - } |
|
| 69 | - |
|
| 70 | - $this->loading[$id] = $id; |
|
| 71 | - try { |
|
| 72 | - return $this->factories[$id]($this); |
|
| 73 | - } finally { |
|
| 74 | - unset($this->loading[$id]); |
|
| 75 | - } |
|
| 76 | - } |
|
| 77 | - |
|
| 78 | - /** |
|
| 79 | - * {@inheritdoc} |
|
| 80 | - */ |
|
| 81 | - public function getProvidedServices(): array |
|
| 82 | - { |
|
| 83 | - if (null === $this->providedTypes) { |
|
| 84 | - $this->providedTypes = []; |
|
| 85 | - |
|
| 86 | - foreach ($this->factories as $name => $factory) { |
|
| 87 | - if (!\is_callable($factory)) { |
|
| 88 | - $this->providedTypes[$name] = '?'; |
|
| 89 | - } else { |
|
| 90 | - $type = (new \ReflectionFunction($factory))->getReturnType(); |
|
| 91 | - |
|
| 92 | - $this->providedTypes[$name] = $type ? ($type->allowsNull() ? '?' : '').($type instanceof \ReflectionNamedType ? $type->getName() : $type) : '?'; |
|
| 93 | - } |
|
| 94 | - } |
|
| 95 | - } |
|
| 96 | - |
|
| 97 | - return $this->providedTypes; |
|
| 98 | - } |
|
| 99 | - |
|
| 100 | - private function createNotFoundException(string $id): NotFoundExceptionInterface |
|
| 101 | - { |
|
| 102 | - if (!$alternatives = array_keys($this->factories)) { |
|
| 103 | - $message = 'is empty...'; |
|
| 104 | - } else { |
|
| 105 | - $last = array_pop($alternatives); |
|
| 106 | - if ($alternatives) { |
|
| 107 | - $message = sprintf('only knows about the "%s" and "%s" services.', implode('", "', $alternatives), $last); |
|
| 108 | - } else { |
|
| 109 | - $message = sprintf('only knows about the "%s" service.', $last); |
|
| 110 | - } |
|
| 111 | - } |
|
| 112 | - |
|
| 113 | - if ($this->loading) { |
|
| 114 | - $message = sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $message); |
|
| 115 | - } else { |
|
| 116 | - $message = sprintf('Service "%s" not found: the current service locator %s', $id, $message); |
|
| 117 | - } |
|
| 118 | - |
|
| 119 | - return new class($message) extends \InvalidArgumentException implements NotFoundExceptionInterface { |
|
| 120 | - }; |
|
| 121 | - } |
|
| 122 | - |
|
| 123 | - private function createCircularReferenceException(string $id, array $path): ContainerExceptionInterface |
|
| 124 | - { |
|
| 125 | - return new class(sprintf('Circular reference detected for service "%s", path: "%s".', $id, implode(' -> ', $path))) extends \RuntimeException implements ContainerExceptionInterface { |
|
| 126 | - }; |
|
| 127 | - } |
|
| 29 | + private $factories; |
|
| 30 | + private $loading = []; |
|
| 31 | + private $providedTypes; |
|
| 32 | + |
|
| 33 | + /** |
|
| 34 | + * @param callable[] $factories |
|
| 35 | + */ |
|
| 36 | + public function __construct(array $factories) |
|
| 37 | + { |
|
| 38 | + $this->factories = $factories; |
|
| 39 | + } |
|
| 40 | + |
|
| 41 | + /** |
|
| 42 | + * {@inheritdoc} |
|
| 43 | + * |
|
| 44 | + * @return bool |
|
| 45 | + */ |
|
| 46 | + public function has(string $id) |
|
| 47 | + { |
|
| 48 | + return isset($this->factories[$id]); |
|
| 49 | + } |
|
| 50 | + |
|
| 51 | + /** |
|
| 52 | + * {@inheritdoc} |
|
| 53 | + * |
|
| 54 | + * @return mixed |
|
| 55 | + */ |
|
| 56 | + public function get(string $id) |
|
| 57 | + { |
|
| 58 | + if (!isset($this->factories[$id])) { |
|
| 59 | + throw $this->createNotFoundException($id); |
|
| 60 | + } |
|
| 61 | + |
|
| 62 | + if (isset($this->loading[$id])) { |
|
| 63 | + $ids = array_values($this->loading); |
|
| 64 | + $ids = \array_slice($this->loading, array_search($id, $ids)); |
|
| 65 | + $ids[] = $id; |
|
| 66 | + |
|
| 67 | + throw $this->createCircularReferenceException($id, $ids); |
|
| 68 | + } |
|
| 69 | + |
|
| 70 | + $this->loading[$id] = $id; |
|
| 71 | + try { |
|
| 72 | + return $this->factories[$id]($this); |
|
| 73 | + } finally { |
|
| 74 | + unset($this->loading[$id]); |
|
| 75 | + } |
|
| 76 | + } |
|
| 77 | + |
|
| 78 | + /** |
|
| 79 | + * {@inheritdoc} |
|
| 80 | + */ |
|
| 81 | + public function getProvidedServices(): array |
|
| 82 | + { |
|
| 83 | + if (null === $this->providedTypes) { |
|
| 84 | + $this->providedTypes = []; |
|
| 85 | + |
|
| 86 | + foreach ($this->factories as $name => $factory) { |
|
| 87 | + if (!\is_callable($factory)) { |
|
| 88 | + $this->providedTypes[$name] = '?'; |
|
| 89 | + } else { |
|
| 90 | + $type = (new \ReflectionFunction($factory))->getReturnType(); |
|
| 91 | + |
|
| 92 | + $this->providedTypes[$name] = $type ? ($type->allowsNull() ? '?' : '').($type instanceof \ReflectionNamedType ? $type->getName() : $type) : '?'; |
|
| 93 | + } |
|
| 94 | + } |
|
| 95 | + } |
|
| 96 | + |
|
| 97 | + return $this->providedTypes; |
|
| 98 | + } |
|
| 99 | + |
|
| 100 | + private function createNotFoundException(string $id): NotFoundExceptionInterface |
|
| 101 | + { |
|
| 102 | + if (!$alternatives = array_keys($this->factories)) { |
|
| 103 | + $message = 'is empty...'; |
|
| 104 | + } else { |
|
| 105 | + $last = array_pop($alternatives); |
|
| 106 | + if ($alternatives) { |
|
| 107 | + $message = sprintf('only knows about the "%s" and "%s" services.', implode('", "', $alternatives), $last); |
|
| 108 | + } else { |
|
| 109 | + $message = sprintf('only knows about the "%s" service.', $last); |
|
| 110 | + } |
|
| 111 | + } |
|
| 112 | + |
|
| 113 | + if ($this->loading) { |
|
| 114 | + $message = sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $message); |
|
| 115 | + } else { |
|
| 116 | + $message = sprintf('Service "%s" not found: the current service locator %s', $id, $message); |
|
| 117 | + } |
|
| 118 | + |
|
| 119 | + return new class($message) extends \InvalidArgumentException implements NotFoundExceptionInterface { |
|
| 120 | + }; |
|
| 121 | + } |
|
| 122 | + |
|
| 123 | + private function createCircularReferenceException(string $id, array $path): ContainerExceptionInterface |
|
| 124 | + { |
|
| 125 | + return new class(sprintf('Circular reference detected for service "%s", path: "%s".', $id, implode(' -> ', $path))) extends \RuntimeException implements ContainerExceptionInterface { |
|
| 126 | + }; |
|
| 127 | + } |
|
| 128 | 128 | } |