mb_ord

Returns the Unicode code point of the first character of a string.

Signature
mb_ord(string $string, ?string $encoding = null): int|false
  • Added in PHP 7.2.0

Parameters

ParameterTypeDescription
$stringstringThe string whose first character is inspected. Any characters after the first are ignored.
$encodingoptional?string= nullThe encoding the string is in. If omitted or null, the internal encoding is used.

Return value

int|falseThe Unicode code point of the first character, or false on failure.

Errors

Throws a ValueError if encoding is not a name mbstring recognises. An empty or malformed first character is reported by returning false.

Changelog

  • PHP 8.0.0encoding became nullable.

mb_ord() is the inverse of mb_chr() and the multibyte replacement for ord(). ord() returns the value of the first byte, so on any non-ASCII character it gives you a lead byte such as 195 rather than the code point you wanted. mb_ord() decodes the whole character and returns its Unicode code point.

Note that it looks only at the first character; everything after it is ignored. To walk a whole string, split it with mb_str_split() and call mb_ord() on each piece.

The result is useful whenever you need to classify characters numerically rather than by pattern: detecting whether a string contains astral-plane characters above U+FFFF (most emoji, which older MySQL utf8 columns cannot store), checking whether input falls inside a specific Unicode block, or generating a stable numeric key. It is also the natural way to produce U+XXXX notation for debugging, via printf('U+%04X', mb_ord($c)).

The return type is int|false. An empty string yields false, and so does a first character that is malformed in the given encoding. Because false compares loosely equal to 0, and 0 is a legitimate code point (NUL), always test with ===.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Detect emoji or other characters above U+FFFF before writing to a database column that cannot hold them.
  • Print U+XXXX notation when debugging an encoding problem.
  • Check whether every character of a name falls inside an allowed Unicode range.
  • Convert a character to a numeric key for a lookup table or checksum.

Frequently asked questions

What is the difference between ord and mb_ord?

ord() returns the numeric value of the first byte, so for a multi-byte character it gives a meaningless lead-byte value such as 195. mb_ord() decodes the full character and returns its Unicode code point.

How do I get the Unicode code point of an emoji in PHP?

Call mb_ord($emoji, 'UTF-8') — for example mb_ord('🐘', 'UTF-8') returns 128024, which is U+1F418. Format it for display with printf('U+%04X', $cp).

Does mb_ord work on a whole string?

No, it only reads the first character and ignores the rest. Split the string with mb_str_split() and call mb_ord() on each character to get every code point.

More examples

Round-trip with mb_chr and walk a string

mb_ord() and mb_chr() are exact inverses for any valid character, which the identity check confirms. Splitting with mb_str_split() first is the standard way to get code points for a whole string, since mb_ord() itself only ever reports on the first character.

Example · php
<?php
$char = "ñ";
$cp   = mb_ord($char, 'UTF-8');

printf("%s = U+%04X\n", $char, $cp);
var_dump(mb_chr($cp, 'UTF-8') === $char);

foreach (mb_str_split("héllo", 1, 'UTF-8') as $c) {
    printf("%s\tU+%04X\n", $c, mb_ord($c, 'UTF-8'));
}

Find characters that will not fit in a three-byte column

Anything above U+FFFF needs four bytes in UTF-8, which is exactly what MySQL's old three-byte utf8 charset cannot store. Testing the code point catches emoji, rare CJK characters and mathematical symbols alike, where a hand-written emoji regex would miss most of them.

Example · php
<?php
function hasAstral(string $s): bool {
    foreach (mb_str_split($s, 1, 'UTF-8') as $c) {
        if (mb_ord($c, 'UTF-8') > 0xFFFF) {
            return true;
        }
    }
    return false;
}

var_dump(hasAstral("plain café"));
var_dump(hasAstral("party 🎉"));

The false return and why === matters

"\0" is a real character with code point 0, while the invalid byte 0xFF returns false. Both report true for a loose == 0 comparison, which is why === 0 is the only safe test for the NUL character. An empty string is different again: since PHP 8 it throws a ValueError rather than returning false.

Example · php
<?php
$cases = ["A", "\0", "\xFF"];

foreach ($cases as $s) {
    $cp = mb_ord($s, 'UTF-8');
    printf("%-8s %-8s loose-zero:%s\n",
        bin2hex($s),
        var_export($cp, true),
        var_export($cp == 0, true)
    );
}

// An empty string is a ValueError, not a false return.
try {
    mb_ord('', 'UTF-8');
} catch (ValueError $e) {
    echo 'ValueError: ', $e->getMessage(), "\n";
}

Discussion

  • Be the first to comment on this lesson.