PHP mbstring Refactoring: Modern Multibyte String Handling Techniques

PHP mbstring Refactoring: Modern Multibyte String Handling Techniques
PHP mbstring Refactoring: Modern Multibyte String Handling Techniques

Ensure your PHP code remains efficient and compatible by updating deprecated mbstring functions. This tutorial explains how to refactor legacy code for modern multibyte string handling.

You bump an old project to PHP 8, hit refresh, and the page dies: Call to undefined function mbereg(). Nothing wrong with your logic. The function just doesn’t exist anymore. That’s the moment most of us meet the mbstring cleanup, and it’s a quick fix once you know what actually changed.

Here’s the short version. A batch of old mbstring names were never anything more than aliases for the real functions. PHP 7.3 deprecated them, PHP 8.0 removed them. So this isn’t about faster code or fancier APIs. It’s about swapping dead names for the canonical ones, and while you’re in there, making sure you’re using the multibyte-aware functions where byte-based ones would quietly corrupt your text.

One thing to check before any of this matters: mbstring is not a default extension. PHP has to be built or configured with it enabled, and plenty of minimal environments ship without it. If mb_strlen() is undefined too, that’s your answer.

Why Multibyte String Functions Are Important

PHP strings are byte arrays. Every classic string function, strlen(), substr(), strtolower(), counts and slices bytes, not characters. For plain ASCII that’s the same thing, so you never notice.

It stops being the same thing the moment you touch UTF-8. A single character in Japanese, Chinese, Korean, Greek, or an emoji can be two, three, or four bytes. Slice that by byte offset and you cut a character in half and hand the user a mojibake mess. The mbstring functions exist to count and cut by character instead, so the text survives.

Deprecated mbstring Functions and Their Replacements

The functions below were undocumented aliases of the mb_-prefixed versions. They did the exact same work, byte for byte. PHP 7.3 marked them deprecated, PHP 8.0 deleted them. If your codebase still calls them, it will fatal on PHP 8. The replacement isn’t an upgrade, it’s the same function under its real name.

1. Replacing mbereg() and mberegi() with mb_ereg() and mb_eregi()

mbereg() and mberegi() are aliases of mb_ereg() and mb_eregi(). Deprecated in PHP 7.3, removed in PHP 8.0. Add the underscore and you’re done.

Example: Refactoring mbereg() to mb_ereg()
PHP
<?php
$pattern = '^hello';
$string  = 'hello world';
// Deprecated function:
if ( mbereg( $pattern, $string ) ) {
    echo 'Match found';
}
// Refactored with modern function:
if ( mb_ereg( $pattern, $string ) ) {
    echo 'Match found';
}

Same behavior, same result. You’re just calling the name PHP still recognizes.

2. Replacing mbsplit() with mb_split()

Same story. mbsplit() is an alias of mb_split(), deprecated in 7.3 and gone in 8.0.

Example: Refactoring mbsplit() to mb_split()
PHP
<?php
$string  = 'PHP is powerful';
$pattern = '\s+';
// Deprecated function:
$words = mbsplit( $pattern, $string );
// Refactored with modern function:
$words = mb_split( $pattern, $string );
print_r( $words );

Output:

Array
(
    [0] => PHP
    [1] => is
    [2] => powerful
)

Nothing changes but the name.

Working with Multibyte Strings: Best Practices

Once the dead names are gone, the harder question is whether you’re handling encoding on purpose. A few habits save you from the subtle bugs:

  • Set your default with mb_internal_encoding( 'UTF-8' ) once, early in the request. Most mb_ functions fall back to it, so this keeps the whole script consistent.
  • When you don’t trust the default, pass the encoding explicitly. Functions like mb_strlen(), mb_substr(), and mb_strtolower() all take an encoding argument, and being explicit at the edges (user input, file reads, API payloads) is worth the extra characters.
  • Replace the removed aliases so the code runs on PHP 8 at all. That’s the forward-compatibility win here, not speed.
Example: Using mb_strlen() for Multibyte Length Calculation

This is where byte-counting bites you. strlen() reports bytes, so a five-character Japanese greeting looks like fifteen:

PHP
<?php
$string = 'こんにちは'; // Japanese "Hello"
// Incorrect byte count using strlen():
echo strlen( $string ); // Output: 15
// Correct character count using mb_strlen():
echo mb_strlen( $string ); // Output: 5

Each of those characters is three bytes in UTF-8, so strlen() returns 15. mb_strlen() counts characters and returns 5, which is what you actually meant. This is the difference that breaks length limits, truncation, and validation when non-ASCII text shows up.

Refactoring Common mbstring Functions
1. Refactoring mb_substr() for Multibyte String Truncation

mb_substr() slices by character, so it never splits a multibyte character down the middle the way substr() would.

Example: Truncating a Multibyte String with mb_substr()
PHP
<?php
$string = 'こんにちは、世界'; // "Hello, world" in Japanese
// Extract the first 5 characters:
$substring = mb_substr( $string, 0, 5 );
echo $substring; // Output: こんにちは

Five characters in, five characters out, all intact. Reach for this any time you truncate user-facing text: teaser copy, previews, anything with a character cap.

2. Refactoring mb_strtolower() and mb_strtoupper()

Case conversion is the other quiet trap. strtolower() and strtoupper() only know ASCII, so anything outside A to Z passes through untouched.

Example: Converting a Multibyte String to Uppercase
PHP
<?php
$string = 'π'; // The Greek letter Pi
// Incorrect uppercase conversion using strtoupper():
echo strtoupper( $string ); // Output: π (no change)
// Correct uppercase conversion using mb_strtoupper():
echo mb_strtoupper( $string ); // Output: Π

strtoupper() leaves the lowercase pi alone because it isn’t ASCII. mb_strtoupper() knows Greek and gives you the capital Π. If you’re normalizing names, search terms, or anything in a real-world language, you want the multibyte version.

Conclusion

Two separate jobs live under one heading here. First, swap the removed aliases (mbereg, mberegi, mbsplit and the rest) for their mb_ names so your code even loads on PHP 8. Second, and more lasting, use the multibyte-aware functions wherever text might not be pure ASCII, and set your encoding on purpose instead of hoping. Do both and non-ASCII text stops being the thing that surprises you in production.

Leave a Comment

Your email address will not be published. Required fields are marked *


Scroll to Top