17
17
*/
18
18
class MbString extends \ArrayObject implements \Stringable
19
19
{
20
+ public const MBSTRING_CONVMETHOD_ICONV = 1 ;
21
+ public const MBSTRING_CONVMETHOD_MBSTRING = 2 ;
22
+
23
+ /**
24
+ * The way to convert text encoding.
25
+ *
26
+ * @var int
27
+ */
28
+ public static $ convMethod ;
29
+
20
30
/**
21
31
* UTF-32 string without endian bytes.
22
32
*
@@ -46,7 +56,8 @@ class MbString extends \ArrayObject implements \Stringable
46
56
*/
47
57
public function __construct (string $ str = '' , string $ encoding = 'UTF-8 ' )
48
58
{
49
- static ::$ utf32Header = static ::$ utf32Header ?? static ::getUtf32Header ();
59
+ static ::$ convMethod ??= static ::detectConvEncoding ();
60
+ static ::$ utf32Header ??= static ::getUtf32Header ();
50
61
51
62
$ this ->encoding = $ encoding ;
52
63
$ this ->set ($ str );
@@ -328,11 +339,37 @@ public function count(): int
328
339
protected static function getUtf32Header (): string
329
340
{
330
341
// just use any string to get the endian header, here we use "A"
331
- $ tmp = iconv ( ' UTF-8 ' , 'UTF-32 ' , 'A ' );
342
+ $ tmp = self :: convEncoding ( ' A ' , 'UTF-8 ' , 'UTF-32 ' );
332
343
// some distributions like "php alpine" docker image won't generate the header
333
344
return $ tmp && \strlen ($ tmp ) > 4 ? substr ($ tmp , 0 , 4 ) : '' ;
334
345
}
335
346
347
+ protected static function detectConvEncoding (): int
348
+ {
349
+ if (\function_exists ('iconv ' ) && iconv ('UTF-8 ' , 'UTF-32 ' , 'A ' ) !== false ) {
350
+ return static ::MBSTRING_CONVMETHOD_ICONV ;
351
+ }
352
+
353
+ if (\function_exists ('mb_convert_encoding ' ) && mb_convert_encoding ('A ' , 'UTF-32 ' , 'UTF-8 ' ) !== false ) {
354
+ return static ::MBSTRING_CONVMETHOD_MBSTRING ;
355
+ }
356
+
357
+ throw new \RuntimeException ('Either "iconv" or "mbstring" extension is required. ' );
358
+ }
359
+
360
+ protected static function convEncoding (string $ str , string $ from , string $ to ): string
361
+ {
362
+ if (static ::$ convMethod === static ::MBSTRING_CONVMETHOD_ICONV ) {
363
+ return iconv ($ from , $ to , $ str );
364
+ }
365
+
366
+ if (static ::$ convMethod === static ::MBSTRING_CONVMETHOD_MBSTRING ) {
367
+ return mb_convert_encoding ($ str , $ to , $ from );
368
+ }
369
+
370
+ throw new \RuntimeException ('Unknown conversion method. ' );
371
+ }
372
+
336
373
/**
337
374
* Convert the output string to its original encoding.
338
375
*
@@ -344,7 +381,7 @@ protected function outputConv(string $str): string
344
381
return '' ;
345
382
}
346
383
347
- return iconv ( 'UTF-32 ' , $ this ->encoding , static :: $ utf32Header . $ str );
384
+ return static :: convEncoding ( static :: $ utf32Header . $ str , 'UTF-32 ' , $ this ->encoding );
348
385
}
349
386
350
387
/**
@@ -358,6 +395,6 @@ protected function inputConv(string $str): string
358
395
return '' ;
359
396
}
360
397
361
- return substr (iconv ( $ this ->encoding , 'UTF-32 ' , $ str ), \strlen (static ::$ utf32Header ));
398
+ return substr (static :: convEncoding ( $ str , $ this ->encoding , 'UTF-32 ' ), \strlen (static ::$ utf32Header ));
362
399
}
363
400
}
0 commit comments