PHP 8.3 Fatal Error: Cannot use string offset as an array – Real World Case
After upgrading to PHP 8.3 you might suddenly see this: Fatal error: Uncaught Error: Cannot use string offset as an array In older PHP versions this often slipped by as a notice or warning. PHP 8.x is stricter, so real bugs now turn into fatal errors.
In simple terms, this error means: you are treating a string like an array.
- 1. Classic real world example: form data overwritten
- 2. JSON decode returning string instead of array
- 3. Database value overriding an array
- 4. Passing string into a function that expects array
- 5. Safely checking types in PHP 8.3
- 6. Quick checklist when you see this error
1. Classic real world example: form data overwritten
Imagine you receive a form and accidentally overwrite an array with a string:
$data = $_POST['user']; // you expect an array
$data = trim($data); // now $data is a string
echo $data['email']; // ❌ Fatal error
$data becomes a string after trim, so $data['email'] tries to use a string offset as an array.
Fix
Keep array and string variables separate or avoid overwriting:
$user = $_POST['user'] ?? [];
$userEmail = isset($user['email']) ? trim($user['email']) : null;
Or, if the form sends flat fields:
$email = isset($_POST['email']) ? trim($_POST['email']) : null;
2. JSON decode returning string instead of array
Another real case: API or database returns JSON, but you double encode it or forget the second parameter in json_decode.
$json = getOption('settings'); // already a JSON string
$settings = json_decode($json); // returns stdClass by default
echo $settings['theme']; // ❌ Fatal error
json_decode without the second parameter returns an object. Accessing it with ['theme'] treats it like an array.
Fix
Decode as an associative array:
$settings = json_decode($json, true); // true = associative array
$theme = $settings['theme'] ?? 'default';
Or keep it as an object and use:
$theme = $settings->theme ?? 'default';
3. Database value overriding an array
You store settings as an array but later load a single column as a string into the same variable:
$config = [
'mail' => [
'host' => 'smtp.example.com',
],
];
$config = $pdo->query('SELECT value FROM config WHERE name="mail"')->fetchColumn();
// now $config is a string from DB
echo $config['host']; // ❌ Fatal error
Fix
Use different variables and convert the DB result back to an array if needed:
$mailConfigJson = $pdo->query(...)->fetchColumn();
$mailConfig = json_decode($mailConfigJson, true) ?? [];
echo $mailConfig['host'] ?? 'localhost';
4. Passing string into a function that expects array
Real world bug from helper functions:
function addDefaultRoles(array $roles): array
{
$roles[] = 'viewer';
return $roles;
}
$rolesFromDb = 'admin'; // bug: should be array
$roles = addDefaultRoles($rolesFromDb); // ❌ Type + string offset errors
PHP may complain that it cannot use string offset internally while trying to push onto the array.
Fix
Normalise types before calling:
$rolesFromDb = $rolesFromDb ? explode(',', $rolesFromDb) : [];
$roles = addDefaultRoles($rolesFromDb);
Or enforce types at the boundary of your application.
5. Safely checking types in PHP 8.3
To avoid this kind of fatal error in new code:
- Use
is_array()before accessing offsets. - Use the null coalescing operator (
??) to provide defaults. - Add strict types and proper type hints.
Example:
declare(strict_types=1);
function getUserEmail(array $user): ?string
{
return isset($user['email']) ? trim((string) $user['email']) : null;
}
$user = $_POST['user'] ?? [];
$email = getUserEmail($user);
Now if $user is not an array, PHP will throw a TypeError at the function boundary instead of failing deep inside your code.
6. Quick checklist when you see this error
- Look at the variable just before you use
$var['key']. var_dumpordd($var)to see its actual type and value.- Stop overwriting arrays with strings in the same variable.
- Decode JSON with
json_decode($json, true)when you want arrays. - Normalise DB and request data as arrays before passing to functions.
- Add type hints and strict types in new PHP 8.3 projects.
Once you treat strings and arrays consistently, this error disappears and your code becomes much easier to reason about in real applications.