Multi-byte-safe substring calculation

@param string $str
@param int $start
@param int $length (optional)
@return string
483441
protected static function ourSubstr($str, $start = 0, $length = null)
    {
        // Premature optimization: cache the function_exists() result
        static $exists = null;
        if ($exists === null) {
            $exists = \function_exists('\\mb_substr');
        }

        // If it exists, we need to make sure we're using 8bit mode
        if ($exists) {
            return \mb_substr($str, $start, $length, '8bit');
        } elseif ($length !== null) {
            return \substr($str, $start, $length);
        }
        return \substr($str, $start);
    }
301501
public static function substr_replace($string, $replacement, $start , $length=null )
    {
        $ret = '';
        if($start>0) $ret .= self::substr($string, 0, $start);
        $ret .= $replacement;
        if($length!=null) $ret .= self::substr($string, $start+$length);
        return $ret;
    }
192452
public function substr($start, $length = null)
  {
    $string = ($length !== null) ? substr($this->string, $start, $length) : substr($this->string, $start);

    return new self($string);
  }
105192
public static function substr($string, $start = 0, $length, $dot = null)
    {
        $string = self::byteSubstr($string, $start, $length);
        return $dot ? $string . $dot : $string;
    }
33121
public static function Substring ($string, $start, $length = null, $encoding = Encoding::DEFAULT_ENCODING) {
		if ($length === null) {
			$length = self::Length($string) - $start;
		}
		return mb_substr($string, $start, $length, $encoding);
	}
916377
public static function shortenString($str, $length = 75, $break = '...') {
        if (strlen($str) < $length)
            return $str;

        $str = strip_tags($str);

        return substr($str, 0, $length) . $break;
    }
380683
public function substr($start, $length = null)
    {
        $str = mb_substr($this->value, $start, $length);

        return static::make($str);
    }
675261
public static function mbSubstr($str, $start = 0, $length = 5, $charset = "utf-8", $suffix = true)
    {
        if (function_exists("mb_substr")) {
            $slice = mb_substr($str, $start, $length, $charset);
        } elseif (function_exists('iconv_substr')) {
            $slice = iconv_substr($str, $start, $length, $charset);
        } else {
            $re['utf-8'] = "/[x01-x7f]|[xc2-xdf][x80-xbf]|[xe0-xef][x80-xbf]{2}|[xf0-xff][x80-xbf]{3}/";
            $re['gb2312'] = "/[x01-x7f]|[xb0-xf7][xa0-xfe]/";
            $re['gbk'] = "/[x01-x7f]|[x81-xfe][x40-xfe]/";
            $re['big5'] = "/[x01-x7f]|[x81-xfe]([x40-x7e]|xa1-xfe])/";
            preg_match_all($re[$charset], $str, $match);
            $slice = join("", array_slice($match[0], $start, $length));
        }
        $fix = '';
        if (strlen($slice) < strlen($str)) {
            $fix = '...';
        }
        
        return $suffix ? $slice . $fix : $slice;
    }
366229
public function substr($str, $offset = 0, $length = null)
    {
        // Due fix of PHP #62759 The third argument returns an empty string if is 0 or null.
        if ($length !== null) {
            return grapheme_substr($str, $offset, $length);
        }

        return grapheme_substr($str, $offset);
    }
648283
static function substr($input, $start, $length = null) {
		if ($length === null) {
			$length = self::length($input) - $start;
		}
		return mb_substr($input, $start, $length, "utf-8");
	}
997418
static public function msubstr($str, $start=0, $length, $charset="utf-8", $suffix=true) {
        if(function_exists("mb_substr"))
            $slice = mb_substr($str, $start, $length, $charset);
        elseif(function_exists('iconv_substr')) {
            $slice = iconv_substr($str,$start,$length,$charset);
        }else{
            $re['utf-8']   = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xff][\x80-\xbf]{3}/";
            $re['gb2312'] = "/[\x01-\x7f]|[\xb0-\xf7][\xa0-\xfe]/";
            $re['gbk']    = "/[\x01-\x7f]|[\x81-\xfe][\x40-\xfe]/";
            $re['big5']   = "/[\x01-\x7f]|[\x81-\xfe]([\x40-\x7e]|\xa1-\xfe])/";
            preg_match_all($re[$charset], $str, $match);
            $slice = join("",array_slice($match[0], $start, $length));
        }
        return $suffix ? $slice.'...' : $slice;
    }
279204
public static function truncate($str, $length, $postFix = '...')
    {
        if (strlen($str) <= $length) {
            return $str;
        }

        return substr($str, 0, ($length - strlen($postFix))) . $postFix;
    }
310797
public function at($start = null, $length = null)
    {
        return new String(mb_substr((string) $this, $start, $length, 'UTF-8'));
    }
893382
public static function slice($string, $start, $length = null)
    {
        if (function_exists('mb_substr')) {
            return mb_substr($string, $start, $length, '8bit');
        }
        return substr($string, $start, $length);
    }
1202848
public function substr(int $start, int $length = null): self
    {
        if ($start < 0) {
            throw new InvalidArgumentException('Negative index is not allowed!');
        }

        return new static(mb_substr($this->data, $start, $length, $this->encoding), $this->encoding);
    }
316634
public static function binarySubstr($str, $start, $length) {
		if (function_exists('mb_substr')) {
			return mb_substr($str, $start, $length, '8bit');
		}

		return substr($string, $start, $length);
	}
1130520
public static function match(string $str, string $start, string $end) {
		$start = preg_quote($start);
		$end = preg_quote($end);
		if (preg_match('/' . $start . '(.*)' . $end . '/', $str, $matches)) {
			return $matches[1] . '';
		}
		return false;
	}