PHP Warnings to Runtime Errors
In the transition from PHP 7.4 to PHP 8.2, notable changes have occurred with certain runtime errors that were previously treated as warnings by PHP. As of PHP 8.x, these errors have been elevated to runtime errors.
Automated tools like Rector can do a lot when it comes to lexical scanning but runtime (non-lexical and more closely tied to the logic and data aspects of code execution) its help is limited.
Defensive coding techniques serve as a robust shield against runtime errors, empowering you to anticipate and prevent such issues.
In our research, we've identified several of these techniques designed to assist you in addressing and rectifying potential errors.
Enable PHP logs
The starting point to identify such errors is to enable PHP logs. This foundational step will provide the necessary data (warnings/errors) so you can implement effective defensive coding to prevent them to happen.
E_WARNING
and E_DEPRECATION
Log in to the PHP error log and test your code.-
Locate your
php.ini
file. The location can vary based on your operating system and PHP installation. Common paths include:- Windows:
C:\Program Files\PHP\php.ini
- Linux:
/etc/php/{version}/apache2/php.ini
- Windows:
-
Open the
php.ini
file in a text editor with administrative privileges. -
Search for the
error_reporting
directive. -
Update the directive to include
E_WARNING
andE_DEPRECATED
:
error_reporting = E_ALL & ~E_NOTICE | E_WARNING | E_DEPRECATED
PHP Warning: count(): Parameter must be an array or an object that implements Countable in *
- safeCount will take care of it
PHP Warning: A non-numeric value encountered*
-
Occurs when invalid strings are coerced using operators expecting numbers (+ - * / ** % << >> | & ^) or their assignment equivalents.
-
Cast the values to int or float before the arithmetic operation.
- Check the values for is_numeric($value) and skip the calculation if the values are not numeric.
PHP Warning: sizeof(): Parameter must be an array or an object that implements Countable in*
- if you have code like
$a = sizeof($b) + 1;
- replace sizeof with
safeCount
PHP Warning: strlen() expects parameter 1 to be string, array given in*
Add defensive for example:
if (is_string($some_value)) { $len = strlen($some_value); } else { // throw error or deal with your data }
PHP Warning: array_key_exists(): The first argument should be either a string or an integer in*
- Add defensive for example:
if ((is_string($haystack) || is_numeric($haystack)) && array_key_exists($haystack, $myArray)) { // continue with your logic } else { // throw error or deal with your data; }
PHP Warning: strpos(): Empty needle in*
- Add defensive code, for example:
if (isset($haystack) && !empty($haystack) && isset($needle) && !empty($needle) && strpos($haystack, $needle, $offset)) { // continue with your logic } else { // throw error or deal with your data; }
PHP Warning: array_intersect(): Expected parameter 1 to be an array, null given in*
- Add defensive for example:
if (is_array($array) && is_array($arrays)) { $intersect = array_intersect($array, $arrays); } else { // throw error or deal with your data; }
PHP Warning: Creating default object from empty value*
- Add defensive for example:
// Option 1: Skip execution branch if the value is not an object $a = BeanFactory::newBean('someweirdstuff'); if (!($a instanceof SugarBean)) { return; } $a->b = 'c'; // Option 2: In cases when the variable is used without being initialized - initialize it first $a = new stdClass(); $a-> b = ‘c’;
PHP Warning: DateTime::diff() expects parameter 1 to be DateTimeInterface, null given*
PHP Warning: DateTime::setTimezone() expects parameter 1 to be DateTimeZone, string given
- Add defensive for example:
$date = new \DateTime(); if ($otherDate instanceof \DateTimeInterface) { $diff = $date->diff($otherDate); }
PHP Warning: Division by zero
- Add defensive for example:
if ($rate != 0) { $result = $amount / $rate; }
PHP Warning: Illegal offset type in isset or empty; PHP Warning: Illegal offset type
-
Array keys can only be int or string. Float, boolean and null get converted transparently (though it may be signal that something went wrong), but arrays, objects and resources don’t.
-
The solution is also defensive coding::
if (is_string($key) || is_int($key)) { $map[$key] = $value; }
PHP Warning: Illegal string offset
-
Array keys can only be int or string. Float, boolean and null get converted transparently (though it may be signal that something went wrong), but arrays, objects and resources don’t.
-
The solution is also defensive coding::
$a = ‘some_string’; if (is_array($a)) { var_dump($a[‘key’]); }
PHP Warning: Use of undefined constant SOME_NAME - assumed 'SOME_NAME'
-
This may have multiple causes, the most common is string literal, not wrapped in quotes.
-
Solution is to wrap these to quotes:
$status = $row['status']; $duration = $n . 'hours';