Signature
mb_strwidth(string $string, ?string $encoding = null): intPurpose
mb_strwidth() estimates how many terminal-style columns a string occupies. Each halfwidth character counts as 1 and each fullwidth character counts as 2. Fullwidth characters include most CJK ideographs, Japanese kana, Korean Hangul syllables and the fullwidth Latin forms. Use it when layout depends on visual columns rather than on bytes or characters, for example in monospaced text tables, console output or fixed-width previews.
Signature
Parameters and defaults
$stringis the text to measure.$encodingnames the character encoding of$string, such as'UTF-8'. If you omit it or passnull, PHP uses the current internal encoding. Passing the encoding explicitly keeps the result independent of global settings.
Return value and failures
The function returns an int: the total width of the string. An empty string has width 0.
Since PHP 8.0.0, an invalid $encoding name throws a ValueError. Before 8.0.0 it emitted a warning instead. Also since 8.0.0, $encoding is nullable.
The manual defines width by a fixed list of code point ranges. Characters inside those ranges, such as U+3000-U+303E, U+3041-U+3096, U+4E00-U+A48C, U+AC00-U+D7A3 and U+FF01-U+FF60, count as 2. Every other character counts as 1.
Example 1: halfwidth and fullwidth characters
The Latin letter a has width 1. Its fullwidth counterpart U+FF41 has width 2. Hiragana characters are fullwidth, so five of them measure 10.
echo json_encode([
mb_strwidth('a', 'UTF-8'),
mb_strwidth("\u{ff41}", 'UTF-8'),
mb_strwidth('Hello', 'UTF-8'),
mb_strwidth('こんにちは', 'UTF-8'),
]);[1,2,5,10]
Example 2: bytes, characters and width are different
Three measurements of the same string answer three different questions. strlen() counts bytes, mb_strlen() counts characters and mb_strwidth() counts display columns.
$text = '日本語';
echo json_encode([
'bytes' => strlen($text),
'chars' => mb_strlen($text, 'UTF-8'),
'width' => mb_strwidth($text, 'UTF-8'),
]);{"bytes":9,"chars":3,"width":6}Example 3: padding to a column width
str_pad() counts bytes, so it misaligns multibyte text. This helper pads by display width instead. max(0, ...) stops it from using a negative repeat count when the text is already too wide.
function padToWidth(string $text, int $width): string
{
$missing = max(0, $width - mb_strwidth($text, 'UTF-8'));
return $text . str_repeat('.', $missing);
}
$rows = ['cat', '犬', 'ねこ'];
echo json_encode(
array_map(fn(string $row): string => padToWidth($row, 6), $rows),
JSON_UNESCAPED_UNICODE
);["cat...","犬....","ねこ.."]
Edge cases
- Empty string: the result is
0. - Mixed text: widths are summed, so
abcplus two fullwidth characters gives 3 + 4 = 7. - Combining marks and emoji: the function follows the manual's range table and nothing more. A character outside the listed ranges counts as 1, even if a terminal or font draws it wider or narrower. A combining accent such as U+0301 is not in the fullwidth list, so it adds 1 to the total.
- Truncated results: the function measures only. To cut a string to a column budget, look at
mb_strimwidth(). - Invalid encoding names:
mb_strwidth('a', 'NOPE')throws aValueError, so catch it if the encoding comes from untrusted input.
Common mistakes
- Using
strlen()orstr_pad()for alignment. These count bytes. A three-character Japanese word occupies nine bytes in UTF-8 but six columns. - Using
mb_strlen()and expecting columns. It counts characters, so a fullwidth character still counts once. - Treating the result as exact rendering width. It is a table-based approximation. Fonts, terminals and emoji sequences may differ.
- Relying on the default encoding. Pass
'UTF-8'explicitly when your data is UTF-8, so changes to the internal encoding cannot alter the answer. - Assuming an error return. Modern PHP throws a
ValueErrorfor a bad encoding, so checking forfalsedoes nothing.
Related functions
mb_strimwidth()truncates a string to a given width.mb_strlen()counts characters.strlen()counts bytes.mb_internal_encoding()gets or sets the default encoding used when$encodingisnull.
Recap
mb_strwidth() returns the number of display columns a string uses, counting fullwidth characters as 2 and all others as 1. It differs from byte and character counts, accepts an optional encoding, and throws a ValueError for an invalid encoding. Use it for column-based layout, and remember that it is an approximation based on a fixed range table.
Tested examples
echo json_encode([
mb_strwidth('a', 'UTF-8'),
mb_strwidth("\u{ff41}", 'UTF-8'),
mb_strwidth('Hello', 'UTF-8'),
mb_strwidth('こんにちは', 'UTF-8'),
]);
[1,2,5,10]
$text = '日本語';
echo json_encode([
'bytes' => strlen($text),
'chars' => mb_strlen($text, 'UTF-8'),
'width' => mb_strwidth($text, 'UTF-8'),
]);
{"bytes":9,"chars":3,"width":6}
function padToWidth(string $text, int $width): string
{
$missing = max(0, $width - mb_strwidth($text, 'UTF-8'));
return $text . str_repeat('.', $missing);
}
$rows = ['cat', '犬', 'ねこ'];
echo json_encode(
array_map(fn(string $row): string => padToWidth($row, 6), $rows),
JSON_UNESCAPED_UNICODE
);
["cat...","犬....","ねこ.."]