Skip to content

Commit 6154b51

Browse files
Merge branch '1.x' into feature/locale_is_right_to_lef
2 parents 667130e + 8e9fcc5 commit 6154b51

19 files changed

+642
-5
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,13 @@ Polyfills are provided for:
7171
- the `array_find`, `array_find_key`, `array_any` and `array_all` functions introduced in PHP 8.4;
7272
- the `Deprecated` attribute introduced in PHP 8.4;
7373
- the `mb_trim`, `mb_ltrim` and `mb_rtrim` functions introduced in PHP 8.4;
74+
- the `ReflectionConstant` class introduced in PHP 8.4
7475
- the `CURL_HTTP_VERSION_3` and `CURL_HTTP_VERSION_3ONLY` constants introduced in PHP 8.4;
76+
- the `grapheme_str_split` function introduced in PHP 8.4;
77+
- the `bcdivmod` function introduced in PHP 8.4;
7578
- the `get_error_handler` and `get_exception_handler` functions introduced in PHP 8.5;
7679
- the `NoDiscard` attribute introduced in PHP 8.5;
80+
- the `array_first` and `array_last` functions introduced in PHP 8.5;
7781

7882
It is strongly recommended to upgrade your PHP version and/or install the missing
7983
extensions whenever possible. This polyfill should be used only when there is no

src/Intl/Grapheme/Grapheme.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
* - grapheme_strrpos - Find position (in grapheme units) of last occurrence of a string
2727
* - grapheme_strstr - Returns part of haystack string from the first occurrence of needle to the end of haystack
2828
* - grapheme_substr - Return part of a string
29+
* - grapheme_str_split - Splits a string into an array of individual or chunks of graphemes
2930
*
3031
* @author Nicolas Grekas <[email protected]>
3132
*
@@ -191,6 +192,37 @@ public static function grapheme_strstr($s, $needle, $beforeNeedle = false)
191192
return mb_strstr($s, $needle, $beforeNeedle, 'UTF-8');
192193
}
193194

195+
public static function grapheme_str_split($s, $len = 1)
196+
{
197+
if (0 > $len || 1073741823 < $len) {
198+
if (80000 > \PHP_VERSION_ID) {
199+
return false;
200+
}
201+
202+
throw new \ValueError('grapheme_str_split(): Argument #2 ($length) must be greater than 0 and less than or equal to 1073741823.');
203+
}
204+
205+
if ('' === $s) {
206+
return [];
207+
}
208+
209+
if (!preg_match_all('/('.SYMFONY_GRAPHEME_CLUSTER_RX.')/u', $s, $matches)) {
210+
return false;
211+
}
212+
213+
if (1 === $len) {
214+
return $matches[0];
215+
}
216+
217+
$chunks = array_chunk($matches[0], $len);
218+
219+
foreach ($chunks as &$chunk) {
220+
$chunk = implode('', $chunk);
221+
}
222+
223+
return $chunks;
224+
}
225+
194226
private static function grapheme_position($s, $needle, $offset, $mode)
195227
{
196228
$needle = (string) $needle;

src/Intl/Grapheme/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ This component provides a partial, native PHP implementation of the
2121
- [`grapheme_strstr`](https://php.net/grapheme_strstr): Returns part of haystack string from
2222
the first occurrence of needle to the end of haystack
2323
- [`grapheme_substr`](https://php.net/grapheme_substr): Return part of a string
24+
- [`grapheme_str_split](https://php.net/grapheme_str_split): Splits a string into an array of individual or chunks of graphemes
2425

2526
More information can be found in the
2627
[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).

src/Intl/Grapheme/bootstrap.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,6 @@ function grapheme_strstr($haystack, $needle, $beforeNeedle = false) { return p\G
5656
if (!function_exists('grapheme_substr')) {
5757
function grapheme_substr($string, $offset, $length = null) { return p\Grapheme::grapheme_substr($string, $offset, $length); }
5858
}
59+
if (!function_exists('grapheme_str_split')) {
60+
function grapheme_str_split($string, $length = 1) { return p\Grapheme::grapheme_str_split($string, $length); }
61+
}

src/Intl/Grapheme/bootstrap80.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,6 @@ function grapheme_strstr(?string $haystack, ?string $needle, ?bool $beforeNeedle
4848
if (!function_exists('grapheme_substr')) {
4949
function grapheme_substr(?string $string, ?int $offset, ?int $length = null): string|false { return p\Grapheme::grapheme_substr((string) $string, (int) $offset, $length); }
5050
}
51+
if (!function_exists('grapheme_str_split')) {
52+
function grapheme_str_split(string $string, int $length = 1): array|false { return p\Grapheme::grapheme_str_split($string, $length); }
53+
}

src/Intl/Icu/NumberFormatter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ public function formatCurrency(float $amount, string $currency)
340340
* @param int $type Type of the formatting, one of the format type constants.
341341
* Only type NumberFormatter::TYPE_DEFAULT is currently supported.
342342
*
343-
* @return bool|string The formatted value or false on error
343+
* @return false|string The formatted value or false on error
344344
*
345345
* @see https://php.net/numberformatter.format
346346
*

src/Php84/Php84.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,4 +174,44 @@ private static function mb_internal_trim(string $regex, string $string, ?string
174174

175175
return mb_convert_encoding($string, $encoding, 'UTF-8');
176176
}
177+
178+
public static function grapheme_str_split(string $string, int $length)
179+
{
180+
if (0 > $length || 1073741823 < $length) {
181+
throw new \ValueError('grapheme_str_split(): Argument #2 ($length) must be greater than 0 and less than or equal to 1073741823.');
182+
}
183+
184+
if ('' === $string) {
185+
return [];
186+
}
187+
188+
$regex = ((float) \PCRE_VERSION < 10 ? (float) \PCRE_VERSION >= 8.32 : (float) \PCRE_VERSION >= 10.39)
189+
? '\X'
190+
: '(?:\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}])';
191+
192+
if (!preg_match_all('/'. $regex .'/u', $string, $matches)) {
193+
return false;
194+
}
195+
196+
if (1 === $length) {
197+
return $matches[0];
198+
}
199+
200+
$chunks = array_chunk($matches[0], $length);
201+
foreach ($chunks as &$chunk) {
202+
$chunk = implode('', $chunk);
203+
}
204+
205+
return $chunks;
206+
}
207+
208+
public static function bcdivmod(string $num1, string $num2, ?int $scale = null): ?array
209+
{
210+
if (null === $quot = \bcdiv($num1, $num2, 0)) {
211+
return null;
212+
}
213+
$scale = $scale ?? (\PHP_VERSION_ID >= 70300 ? \bcscale() : (ini_get('bcmath.scale') ?: 0));
214+
215+
return [$quot, \bcmod($num1, $num2, $scale)];
216+
}
177217
}

src/Php84/README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@ Symfony Polyfill / Php84
33

44
This component provides features added to PHP 8.4 core:
55

6-
- [`mb_ucfirst` and `mb_lcfirst`](https://wiki.php.net/rfc/mb_ucfirst)
76
- [`array_find`, `array_find_key`, `array_any` and `array_all`](https://wiki.php.net/rfc/array_find)
7+
- [`bcdivmod`](https://wiki.php.net/rfc/add_bcdivmod_to_bcmath)
88
- [`Deprecated`](https://wiki.php.net/rfc/deprecated_attribute)
99
- `CURL_HTTP_VERSION_3` and `CURL_HTTP_VERSION_3ONLY` constants
1010
- [`fpow`](https://wiki.php.net/rfc/raising_zero_to_power_of_negative_number)
11+
- [`grapheme_str_split`](https://wiki.php.net/rfc/grapheme_str_split)
1112
- [`mb_trim`, `mb_ltrim` and `mb_rtrim`](https://wiki.php.net/rfc/mb_trim)
13+
- [`mb_ucfirst` and `mb_lcfirst`](https://wiki.php.net/rfc/mb_ucfirst)
14+
- [`ReflectionConstant`](https://github.com/php/php-src/pull/13669)
1215

1316
More information can be found in the
1417
[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
if (\PHP_VERSION_ID < 80400) {
13+
/**
14+
* @author Daniel Scherzer <[email protected]>
15+
*/
16+
final class ReflectionConstant
17+
{
18+
/**
19+
* @var string
20+
*
21+
* @readonly
22+
*/
23+
public $name;
24+
25+
private $value;
26+
private $deprecated;
27+
28+
private static $persistentConstants = [];
29+
30+
public function __construct(string $name)
31+
{
32+
if (!defined($name) || false !== strpos($name, '::')) {
33+
throw new ReflectionException("Constant \"$name\" does not exist");
34+
}
35+
36+
$this->name = ltrim($name, '\\');
37+
$deprecated = false;
38+
$eh = set_error_handler(static function ($type, $msg, $file, $line) use ($name, &$deprecated, &$eh) {
39+
if (\E_DEPRECATED === $type && "Constant $name is deprecated" === $msg) {
40+
return $deprecated = true;
41+
}
42+
43+
return $eh && $eh($type, $msg, $file, $line);
44+
});
45+
46+
try {
47+
$this->value = constant($name);
48+
$this->deprecated = $deprecated;
49+
} finally {
50+
restore_error_handler();
51+
}
52+
}
53+
54+
public function getName(): string
55+
{
56+
return $this->name;
57+
}
58+
59+
public function getValue()
60+
{
61+
return $this->value;
62+
}
63+
64+
public function getNamespaceName(): string
65+
{
66+
if (false === $slashPos = strrpos($this->name, '\\')) {
67+
return '';
68+
}
69+
70+
return substr($this->name, 0, $slashPos);
71+
}
72+
73+
public function getShortName(): string
74+
{
75+
if (false === $slashPos = strrpos($this->name, '\\')) {
76+
return $this->name;
77+
}
78+
79+
return substr($this->name, $slashPos + 1);
80+
}
81+
82+
public function isDeprecated(): bool
83+
{
84+
return $this->deprecated;
85+
}
86+
87+
public function __toString(): string
88+
{
89+
// A constant is persistent if provided by PHP itself rather than
90+
// being defined by users. If we got here, we know that it *is*
91+
// defined, so we just need to figure out if it is defined by the
92+
// user or not
93+
if (!self::$persistentConstants) {
94+
$persistentConstants = get_defined_constants(true);
95+
unset($persistentConstants['user']);
96+
foreach ($persistentConstants as $constants) {
97+
self::$persistentConstants += $constants;
98+
}
99+
}
100+
$persistent = array_key_exists($this->name, self::$persistentConstants);
101+
102+
// Can't match the inclusion of `no_file_cache` but the rest is
103+
// possible to match
104+
$result = 'Constant [ ';
105+
if ($persistent || $this->deprecated) {
106+
$result .= '<';
107+
if ($persistent) {
108+
$result .= 'persistent';
109+
if ($this->deprecated) {
110+
$result .= ', ';
111+
}
112+
}
113+
if ($this->deprecated) {
114+
$result .= 'deprecated';
115+
}
116+
$result .= '> ';
117+
}
118+
// Cannot just use gettype() to match zend_zval_type_name()
119+
if (is_object($this->value)) {
120+
$result .= \PHP_VERSION_ID >= 80000 ? get_debug_type($this->value) : gettype($this->value);
121+
} elseif (is_bool($this->value)) {
122+
$result .= 'bool';
123+
} elseif (is_int($this->value)) {
124+
$result .= 'int';
125+
} elseif (is_float($this->value)) {
126+
$result .= 'float';
127+
} elseif (null === $this->value) {
128+
$result .= 'null';
129+
} else {
130+
$result .= gettype($this->value);
131+
}
132+
$result .= ' ';
133+
$result .= $this->name;
134+
$result .= ' ] { ';
135+
if (is_array($this->value)) {
136+
$result .= 'Array';
137+
} else {
138+
// This will throw an exception if the value is an object that
139+
// cannot be converted to string; that is expected and matches
140+
// the behavior of zval_get_string_func()
141+
$result .= (string) $this->value;
142+
}
143+
$result .= " }\n";
144+
145+
return $result;
146+
}
147+
148+
public function __sleep(): array
149+
{
150+
throw new Exception("Serialization of 'ReflectionConstant' is not allowed");
151+
}
152+
153+
public function __wakeup(): void
154+
{
155+
throw new Exception("Unserialization of 'ReflectionConstant' is not allowed");
156+
}
157+
}
158+
}

src/Php84/bootstrap.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,17 @@ function mb_ltrim(string $string, ?string $characters = null, ?string $encoding
6666
function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Php84::mb_rtrim($string, $characters, $encoding); }
6767
}
6868
}
69+
70+
if (extension_loaded('bcmath')) {
71+
if (!function_exists('bcdivmod')) {
72+
function bcdivmod(string $num1, string $num2, ?int $scale = null): ?array { return p\Php84::bcdivmod($num1, $num2, $scale); }
73+
}
74+
}
75+
76+
if (\PHP_VERSION_ID >= 80200) {
77+
return require __DIR__.'/bootstrap82.php';
78+
}
79+
80+
if (extension_loaded('intl') && !function_exists('grapheme_str_split')) {
81+
function grapheme_str_split(string $string, int $length = 1) { return p\Php84::grapheme_str_split($string, $length); }
82+
}

0 commit comments

Comments
 (0)