Common causes
- Reading $_GET, $_POST or $_SERVER values that were not sent with the request
- Code written for PHP 7 that relied on notices being hidden
- A typo or different case in the key name
- Numeric index past the end of the array, such as $parts[1] after an explode() with no delimiter found
- An API or database result missing a field you expected
How to fix it
- Use the null coalescing operator. Replace $id = $_GET['id']; with $id = $_GET['id'] ?? null; or a sensible default. The ?? operator does not raise a warning for missing keys.
- Check before using. Wrap logic in if (isset($data['key'])) { ... }. Use array_key_exists('key', $data) when a null value is valid and must be distinguished from a missing key.
- Validate input explicitly. For request data use filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT), which returns null when the parameter is missing and false when it is invalid.
- Fix the data source. Use var_dump(array_keys($data)) or print_r to see which keys actually exist. Correct typos or handle the case where an API omits the field.
- Hide warnings in production while you fix them. Set display_errors = Off and log_errors = On in production so visitors never see the warning. This does not fix the bug, so keep working through the log.
Safe reads in PHP 8
<?php
$id = $_GET['id'] ?? null; // default if missing
$page = (int) ($_GET['page'] ?? 1);
$ref = $_SERVER['HTTP_REFERER'] ?? '';
if (array_key_exists('email', $row)) {
// key exists, value may be null
}
[$user, $domain] = array_pad(explode('@', $email, 2), 2, null); How to stop it happening again
- Run tests with error_reporting = E_ALL so warnings show up during development
- Use ?? defaults for all request and config values
- Use typed DTOs or validated arrays for API responses
- Use static analysis such as PHPStan or Psalm to catch unsafe array access