diff --git a/composer.json b/composer.json index e79e33d..fcc3562 100644 --- a/composer.json +++ b/composer.json @@ -36,6 +36,10 @@ "phan/phan": "^5", "phpunit/phpunit": "^9 || ^10" }, + "suggest": { + "ext-iconv": "Either \"ext-iconv\" or \"ext-mbstring\" is requried.", + "ext-mbstring": "Either \"ext-iconv\" or \"ext-mbstring\" is requried." + }, "scripts": { "analyze": [ "phan --color" diff --git a/composer.lock b/composer.lock index 2672401..aec74fe 100644 --- a/composer.lock +++ b/composer.lock @@ -1133,16 +1133,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.18.1", + "version": "1.19.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "22dcdfd725ddf99583bfe398fc624ad6c5004a0f" + "reference": "178b33aa1c8b8d7725f0abee618ef47337e607ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/22dcdfd725ddf99583bfe398fc624ad6c5004a0f", - "reference": "22dcdfd725ddf99583bfe398fc624ad6c5004a0f", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/178b33aa1c8b8d7725f0abee618ef47337e607ce", + "reference": "178b33aa1c8b8d7725f0abee618ef47337e607ce", "shasum": "" }, "require": { @@ -1172,9 +1172,9 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.18.1" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.19.0" }, - "time": "2023-04-07T11:51:11+00:00" + "time": "2023-04-17T13:16:52+00:00" }, { "name": "phpunit/php-code-coverage", diff --git a/src/MbString.php b/src/MbString.php index 6f38188..a32b751 100644 --- a/src/MbString.php +++ b/src/MbString.php @@ -17,6 +17,16 @@ */ class MbString extends \ArrayObject implements \Stringable { + public const MBSTRING_CONVMETHOD_ICONV = 1; + public const MBSTRING_CONVMETHOD_MBSTRING = 2; + + /** + * The way to convert text encoding. + * + * @var int + */ + public static $convMethod; + /** * UTF-32 string without endian bytes. * @@ -46,7 +56,8 @@ class MbString extends \ArrayObject implements \Stringable */ public function __construct(string $str = '', string $encoding = 'UTF-8') { - static::$utf32Header = static::$utf32Header ?? static::getUtf32Header(); + static::$convMethod ??= static::detectConvEncoding(); + static::$utf32Header ??= static::getUtf32Header(); $this->encoding = $encoding; $this->set($str); @@ -328,11 +339,37 @@ public function count(): int protected static function getUtf32Header(): string { // just use any string to get the endian header, here we use "A" - $tmp = iconv('UTF-8', 'UTF-32', 'A'); + $tmp = self::convEncoding('A', 'UTF-8', 'UTF-32'); // some distributions like "php alpine" docker image won't generate the header return $tmp && \strlen($tmp) > 4 ? substr($tmp, 0, 4) : ''; } + protected static function detectConvEncoding(): int + { + if (\function_exists('iconv') && iconv('UTF-8', 'UTF-32', 'A') !== false) { + return static::MBSTRING_CONVMETHOD_ICONV; + } + + if (\function_exists('mb_convert_encoding') && mb_convert_encoding('A', 'UTF-32', 'UTF-8') !== false) { + return static::MBSTRING_CONVMETHOD_MBSTRING; + } + + throw new \RuntimeException('Either "iconv" or "mbstring" extension is required.'); + } + + protected static function convEncoding(string $str, string $from, string $to): string + { + if (static::$convMethod === static::MBSTRING_CONVMETHOD_ICONV) { + return iconv($from, $to, $str); + } + + if (static::$convMethod === static::MBSTRING_CONVMETHOD_MBSTRING) { + return mb_convert_encoding($str, $to, $from); + } + + throw new \RuntimeException('Unknown conversion method.'); + } + /** * Convert the output string to its original encoding. * @@ -344,7 +381,7 @@ protected function outputConv(string $str): string return ''; } - return iconv('UTF-32', $this->encoding, static::$utf32Header . $str); + return static::convEncoding(static::$utf32Header . $str, 'UTF-32', $this->encoding); } /** @@ -358,6 +395,6 @@ protected function inputConv(string $str): string return ''; } - return substr(iconv($this->encoding, 'UTF-32', $str), \strlen(static::$utf32Header)); + return substr(static::convEncoding($str, $this->encoding, 'UTF-32'), \strlen(static::$utf32Header)); } }