code: private function conv($str)
      {
          // prefer mb_convert_encoding if available
          if ($this->supportsExtMbstring) {
              return mb_convert_encoding($str, 'UTF-8', 'UTF-16BE');
          }
  
          // Otherwise convert each byte pair to its Unicode code point and
          // then manually encode as UTF-8 bytes.
          return preg_replace_callback('/(?:[\xD8-\xDB]...)|(?:..)/s', function ($m) {
              if (isset($m[0][3])) {
                  // U+10000 - U+10FFFF uses four UTF-16 bytes and 4 UTF-8 bytes
                  // get code point from higher and lower surrogate and convert
                  list(, $higher, $lower) = unpack('n*', $m[0]);
                  $code = (($higher & 0x03FF) << 10) + ($lower & 0x03FF) + 0x10000;
  
                  return pack(
                      'c*',
                      $code >> 18 | 0xF0,
                      $code >> 12 & 0x3F | 0x80,
                      $code >> 6 & 0x3F | 0x80,
                      $code & 0x3F | 0x80
                  );
              }
  
              list(, $code) = unpack('n', $m[0]);
              if ($code < 0x80) {
                  // U+0000 - U+007F encodes as single ASCII/UTF-8 byte
                  return chr($code);
              } elseif ($code < 0x0800) {
                  // U+0080 - U+07FF encodes as two UTF-8 bytes
                  return chr($code >> 6 | 0xC0) . chr($code & 0x3F | 0x80);
              } else {
                  // U+0800 - U+FFFF encodes as three UTF-8 bytes
                  return chr($code >> 12 | 0xE0) . chr($code >> 6 & 0x3F | 0x80) . chr($code & 0x3F | 0x80);
              }
              return '?';
          }, $str);
      }
docs: transcode UTF-16BE to UTF-8
  
  @param string $str
  @return string