Strings7 min readExamples run on PHP 8.5.10

strtoupper()

Learn how PHP 8.4 strtoupper() converts ASCII letters to uppercase, how it treats UTF-8 text, and which mistakes to avoid.

Signature

strtoupper(string $string): string

Purpose

strtoupper() returns a copy of a string in which every ASCII lowercase letter has been replaced by its uppercase form. It is a small, fast tool for normalizing identifiers, coupon codes, header names, and other machine-oriented text where you want a single canonical spelling.

The function works on bytes. Each byte from a (0x61) to z (0x7a) is converted by subtracting 32. Every other byte is copied unchanged, including digits, punctuation, whitespace and any byte that belongs to a multibyte character. The original string is never modified; you must use the returned value.

Signature

Parameters and defaults

  • $string: the input string. It is required and has no default value.

There are no optional parameters. In particular, you cannot pass a locale or an encoding. The documented changelog states that since PHP 8.2.0 the conversion no longer depends on the locale set with setlocale(), and only ASCII characters are converted. So the result for a given input is the same on every machine running PHP 8.4.

Return value and failure cases

The function always returns a string, and the result has the same length in bytes as the input. It does not return false and does not signal failure through a return value.

Because the parameter is typed string, wrong argument types are handled by PHP's normal type rules:

  • Passing an array (or an object without __toString()) throws a TypeError.
  • In the default coercive typing mode, a scalar such as an integer is converted to its string form first, so strtoupper(123) gives "123".
  • With declare(strict_types=1); in the calling file, passing an integer throws a TypeError instead of being coerced.

The manual also notes that the function is binary-safe, meaning strings containing NUL bytes are processed in full rather than being cut off.

Example 1: normalizing a code

User input often arrives with stray spaces and mixed case. Combining trim() and strtoupper() gives a stable form for lookups.

Example
<?php
$input = "  save10 ";
$code = strtoupper(trim($input));
echo $code, "\n";
Output
SAVE10

The output is SAVE10 followed by a newline. Note that trim() removes the surrounding whitespace first; strtoupper() does not touch whitespace.

Example 2: UTF-8 text is only partly converted

Because only ASCII letters are changed, accented letters and other non-ASCII characters keep their original case. The multibyte bytes are simply ignored, so the UTF-8 text stays valid, but it may look half-converted.

Example
<?php
$text = "café ñandú straße";
echo json_encode(['upper' => strtoupper($text)], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
Output
{"upper":"CAFé ñANDú STRAßE"}

The result is {"upper":"CAFé ñANDú STRAßE"}. The letters c, a, f, a, n, d and so on are uppercased, but é, ñ, ú and ß are left as they were. If you need full Unicode case conversion, the manual points to mb_strtoupper(), which belongs to the mbstring extension.

Example 3: canonical array keys

HTTP-style header names are case-insensitive, so a common pattern is to rebuild an array with uppercased keys.

Example
<?php
$headers = ["content-type" => "text/plain", "X-Request-Id" => "abc"];
$normalized = [];
foreach ($headers as $name => $value) {
    $normalized[strtoupper($name)] = $value;
}
echo json_encode($normalized, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
Output
{"CONTENT-TYPE":"text/plain","X-REQUEST-ID":"abc"}

The output is {"CONTENT-TYPE":"text/plain","X-REQUEST-ID":"abc"}. Only the keys change; the values keep their original case, which matters because text/plain is data, not a name.

Edge cases

  • Empty string: returns an empty string.
  • No letters: a string such as "123-456" is returned unchanged.
  • Already uppercase: the result equals the input.
  • Collisions: two different keys such as "id" and "ID" become identical after conversion. When you rebuild an array, the later one overwrites the earlier one.
  • Non-UTF-8 bytes: bytes outside the ASCII lowercase range are never altered, so legacy single-byte encodings are not converted either.
  • Length: the result has the same byte length as the input, unlike full Unicode uppercasing, where one character can expand into several (for example ß to SS).

Common mistakes

  1. Ignoring the return value. Writing strtoupper($name); on its own statement has no effect. Assign the result: $name = strtoupper($name);.
  2. Expecting Unicode support. Names like "Zoë" will become "ZOë". Use mb_strtoupper() for human-language text in non-ASCII scripts, provided the mbstring extension is available.
  3. Relying on locale. Older advice suggested calling setlocale() to change how accented letters convert. As the changelog says, since PHP 8.2.0 the locale no longer affects this function.
  4. Using it for display capitalization. Uppercasing every character is not the same as title case. Look at ucfirst() or ucwords() when you want to capitalize only initial letters.
  5. Passing arrays. Passing an array throws a TypeError; apply the function to each element, for example with array_map().
  6. Comparing before normalizing both sides. When doing a case-insensitive comparison, convert both strings the same way, or use a dedicated function like strcasecmp().
  • strtolower(): makes a string lowercase, using the same ASCII-only rule.
  • ucfirst(): uppercases only the first character.
  • ucwords(): uppercases the first character of each word.
  • mb_strtoupper(): converts multibyte characters, not just ASCII.

Recap

strtoupper() takes one string and returns a new string where ASCII a to z are turned into A to Z. Everything else, including UTF-8 multibyte characters, passes through unchanged. Since PHP 8.2.0 it ignores the current locale. Use it for normalizing ASCII identifiers and keys, always use the returned value, and switch to mb_strtoupper() when real Unicode case mapping is needed.

Tested examples

Normalizing a coupon code
<?php
$input = "  save10 ";
$code = strtoupper(trim($input));
echo $code, "\n";
Output
SAVE10
UTF-8 text is only partly converted
<?php
$text = "café ñandú straße";
echo json_encode(['upper' => strtoupper($text)], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
Output
{"upper":"CAFé ñANDú STRAßE"}
Canonical array keys
<?php
$headers = ["content-type" => "text/plain", "X-Request-Id" => "abc"];
$normalized = [];
foreach ($headers as $name => $value) {
    $normalized[strtoupper($name)] = $value;
}
echo json_encode($normalized, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
Output
{"CONTENT-TYPE":"text/plain","X-REQUEST-ID":"abc"}