Take the State of PHP 2026 Survey →

Reclassifying engine warnings View as Markdown

Implemented (PHP 8.0)
Authors
Nikita Popov nikic@php.net
Date
2019-08-27
Target
PHP 8.0
Source
wiki.php.net/rfc/engine_warnings

Votes

Change undefined variable severity to? closed
Error exception
36
Warning
18
Keep Notice
10
64 voters
alcaeus Error exception 2019-09-12 14:07
as Warning 2019-09-13 05:42
ashnazg Error exception 2019-09-12 19:47
beberlei Warning 2019-09-12 12:34
brzuchal Error exception 2019-09-12 12:20
bs Error exception 2019-09-12 13:30
bwoebi Warning 2019-09-17 11:41
carusogabriel Error exception 2019-09-12 13:25
chregu Warning 2019-09-13 11:13
cmb Warning 2019-09-13 08:38
cschneid Keep Notice 2019-09-12 12:25
dams Warning 2019-09-16 13:44
daverandom Error exception 2019-09-16 08:25
derick Warning 2019-09-13 08:10
dmitry Error exception 2019-09-19 22:54
dragoonis Error exception 2019-09-14 21:04
duncan3dc Error exception 2019-09-12 18:17
eliw Error exception 2019-09-12 19:22
galvao Error exception 2019-09-13 10:25
gasolwu Error exception 2019-09-12 13:21
girgias Error exception 2019-09-12 12:11
guilhermeblanco Error exception 2019-09-13 02:21
heiglandreas Warning 2019-09-13 05:47
ircmaxell Keep Notice 2019-09-13 15:43
jasny Warning 2019-09-12 22:00
jhdxr Error exception 2019-09-12 16:42
jpauli Warning 2019-09-12 17:49
kalle Error exception 2019-09-12 15:02
kelunik Warning 2019-09-12 21:47
keyur Error exception 2019-09-14 01:56
kguest Error exception 2019-09-23 13:30
klaussilveira Error exception 2019-09-12 15:25
krakjoe Error exception 2019-09-12 23:28
laruence Keep Notice 2019-09-26 06:18
lcobucci Error exception 2019-09-13 22:52
levim Error exception 2019-09-12 13:55
malukenho Error exception 2019-09-24 15:07
marandall Error exception 2019-09-14 21:35
mbeccati Keep Notice 2019-09-15 16:58
mcmic Warning 2019-09-17 07:47
mrook Error exception 2019-09-23 08:36
narf Error exception 2019-09-17 05:22
nikic Error exception 2019-09-12 12:03
ocramius Error exception 2019-09-12 12:13
pajoye Error exception 2019-09-23 15:06
patrickallaert Warning 2019-09-23 13:13
petk Error exception 2019-09-15 11:52
pmmaga Warning 2019-09-24 10:18
pollita Warning 2019-09-16 20:12
ralphschindler Keep Notice 2019-09-19 21:08
ramsey Keep Notice 2019-09-15 20:39
rasmus Keep Notice 2019-09-15 02:52
reywob Warning 2019-09-12 12:42
salathe Keep Notice 2019-09-12 15:05
santiagolizardo Warning 2019-09-12 22:17
sebastian Error exception 2019-09-12 12:24
seld Warning 2019-09-12 14:54
sergey Error exception 2019-09-12 12:18
stas Keep Notice 2019-09-12 16:55
svpernova09 Error exception 2019-09-12 12:49
till Error exception 2019-09-23 16:12
trowski Error exception 2019-09-12 14:15
wyrihaximus Error exception 2019-09-18 20:06
zimt Keep Notice 2019-09-24 16:20
Change undefined array index severity to? closed
Warning
42
Keep Notice
21
63 voters
alcaeus Warning 2019-09-12 14:07
as Warning 2019-09-13 05:43
ashnazg Warning 2019-09-12 19:48
beberlei Keep Notice 2019-09-12 21:30
brzuchal Warning 2019-09-12 12:21
bs Warning 2019-09-12 13:30
bwoebi Warning 2019-09-13 14:39
carusogabriel Warning 2019-09-12 13:25
chregu Keep Notice 2019-09-13 11:15
cmb Keep Notice 2019-09-13 08:38
cschneid Keep Notice 2019-09-12 12:25
dams Warning 2019-09-16 13:44
derick Warning 2019-09-12 14:43
dmitry Keep Notice 2019-09-25 13:44
duncan3dc Warning 2019-09-12 18:18
eliw Keep Notice 2019-09-12 19:22
galvao Warning 2019-09-13 10:25
gasolwu Warning 2019-09-12 13:23
girgias Warning 2019-09-12 12:12
guilhermeblanco Warning 2019-09-13 02:22
heiglandreas Warning 2019-09-13 05:48
ircmaxell Keep Notice 2019-09-12 16:42
jasny Keep Notice 2019-09-12 21:52
jhdxr Keep Notice 2019-09-12 16:43
jpauli Warning 2019-09-12 17:49
kalle Warning 2019-09-12 15:03
kelunik Warning 2019-09-12 21:48
keyur Warning 2019-09-14 01:56
kguest Warning 2019-09-23 13:31
klaussilveira Warning 2019-09-12 15:25
krakjoe Warning 2019-09-12 23:29
laruence Keep Notice 2019-09-26 06:21
lcobucci Warning 2019-09-13 22:52
levim Warning 2019-09-12 13:47
malukenho Warning 2019-09-24 15:07
marandall Warning 2019-09-14 21:36
mbeccati Keep Notice 2019-09-12 16:34
mcmic Warning 2019-09-17 07:46
mrook Warning 2019-09-23 08:37
narf Warning 2019-09-17 05:22
nikic Warning 2019-09-12 12:03
ocramius Warning 2019-09-12 12:13
pajoye Warning 2019-09-23 15:07
patrickallaert Keep Notice 2019-09-24 15:38
petk Warning 2019-09-15 11:46
pmmaga Warning 2019-09-24 10:18
pollita Warning 2019-09-16 20:13
ralphschindler Keep Notice 2019-09-19 21:08
ramsey Keep Notice 2019-09-15 20:40
rasmus Keep Notice 2019-09-12 23:58
reywob Keep Notice 2019-09-12 12:40
salathe Keep Notice 2019-09-12 15:06
santiagolizardo Warning 2019-09-12 22:16
sebastian Warning 2019-09-12 12:24
seld Keep Notice 2019-09-12 15:01
sergey Warning 2019-09-12 12:19
stas Keep Notice 2019-09-12 16:55
svpernova09 Warning 2019-09-12 12:50
till Warning 2019-09-23 16:12
trowski Warning 2019-09-12 14:15
wyrihaximus Warning 2019-09-18 20:07
zeev Keep Notice 2019-09-12 12:39
zimt Keep Notice 2019-09-24 16:20
Change division by zero severity to? closed
DivisionByZeroError exception
52
Keep Warning
8
60 voters
alcaeus DivisionByZeroError exception 2019-09-12 14:07
as DivisionByZeroError exception 2019-09-13 05:41
ashnazg DivisionByZeroError exception 2019-09-12 19:48
beberlei Keep Warning 2019-09-12 14:11
brzuchal DivisionByZeroError exception 2019-09-12 12:21
bs DivisionByZeroError exception 2019-09-12 13:30
bwoebi Keep Warning 2019-09-13 14:40
carusogabriel DivisionByZeroError exception 2019-09-12 13:25
chregu DivisionByZeroError exception 2019-09-13 11:14
cmb Keep Warning 2019-09-13 08:38
cschneid Keep Warning 2019-09-12 12:24
dams DivisionByZeroError exception 2019-09-16 13:45
derick DivisionByZeroError exception 2019-09-12 14:44
dragoonis DivisionByZeroError exception 2019-09-14 21:12
duncan3dc DivisionByZeroError exception 2019-09-12 18:18
eliw DivisionByZeroError exception 2019-09-12 19:23
galvao DivisionByZeroError exception 2019-09-13 10:26
gasolwu DivisionByZeroError exception 2019-09-12 13:22
girgias Keep Warning 2019-09-12 13:54
guilhermeblanco DivisionByZeroError exception 2019-09-13 02:22
heiglandreas DivisionByZeroError exception 2019-09-13 05:48
ircmaxell DivisionByZeroError exception 2019-09-12 16:42
jasny DivisionByZeroError exception 2019-09-12 21:52
jhdxr DivisionByZeroError exception 2019-09-12 16:44
jpauli DivisionByZeroError exception 2019-09-12 17:50
kalle DivisionByZeroError exception 2019-09-12 15:03
kelunik DivisionByZeroError exception 2019-09-12 21:48
keyur DivisionByZeroError exception 2019-09-14 01:56
kguest DivisionByZeroError exception 2019-09-23 13:31
klaussilveira DivisionByZeroError exception 2019-09-12 15:25
krakjoe DivisionByZeroError exception 2019-09-12 23:29
laruence Keep Warning 2019-09-26 06:22
lcobucci DivisionByZeroError exception 2019-09-13 22:52
levim Keep Warning 2019-09-12 13:54
malukenho DivisionByZeroError exception 2019-09-24 15:07
marandall DivisionByZeroError exception 2019-09-14 21:36
mbeccati DivisionByZeroError exception 2019-09-12 16:35
mrook DivisionByZeroError exception 2019-09-23 08:37
narf DivisionByZeroError exception 2019-09-17 05:22
ocramius DivisionByZeroError exception 2019-09-12 12:14
pajoye DivisionByZeroError exception 2019-09-23 15:07
patrickallaert DivisionByZeroError exception 2019-09-24 15:37
petk DivisionByZeroError exception 2019-09-15 11:49
pmmaga DivisionByZeroError exception 2019-09-24 10:18
pollita DivisionByZeroError exception 2019-09-16 20:13
ralphschindler DivisionByZeroError exception 2019-09-19 21:08
ramsey DivisionByZeroError exception 2019-09-15 20:41
rasmus DivisionByZeroError exception 2019-09-12 23:57
reywob DivisionByZeroError exception 2019-09-12 12:45
salathe Keep Warning 2019-09-12 15:06
santiagolizardo DivisionByZeroError exception 2019-09-12 22:17
sebastian DivisionByZeroError exception 2019-09-12 12:25
sergey DivisionByZeroError exception 2019-09-12 12:19
stas DivisionByZeroError exception 2019-09-12 16:56
svpernova09 DivisionByZeroError exception 2019-09-12 12:50
till DivisionByZeroError exception 2019-09-23 16:12
trowski DivisionByZeroError exception 2019-09-12 14:15
wyrihaximus DivisionByZeroError exception 2019-09-18 20:07
zeev DivisionByZeroError exception 2019-09-13 04:55
zimt DivisionByZeroError exception 2019-09-24 16:21
Accept remaining classifications shown in the table above? closed
Yes
54
No
3
57 voters
alcaeus Yes 2019-09-12 14:07
as Yes 2019-09-13 05:42
ashnazg Yes 2019-09-12 19:49
beberlei Yes 2019-09-12 12:38
brzuchal Yes 2019-09-12 12:21
bs Yes 2019-09-12 13:30
bwoebi Yes 2019-09-13 14:40
carusogabriel Yes 2019-09-12 13:25
chregu Yes 2019-09-13 11:14
cmb Yes 2019-09-13 08:39
cschneid No 2019-09-12 12:24
dams Yes 2019-09-16 13:45
derick Yes 2019-09-12 14:45
dmitry Yes 2019-09-19 23:00
dragoonis Yes 2019-09-14 21:13
duncan3dc Yes 2019-09-12 18:19
eliw Yes 2019-09-12 19:23
galvao Yes 2019-09-13 10:26
gasolwu Yes 2019-09-12 13:22
girgias Yes 2019-09-12 12:11
guilhermeblanco Yes 2019-09-13 02:22
heiglandreas Yes 2019-09-13 05:49
jasny Yes 2019-09-12 21:53
jpauli Yes 2019-09-12 17:50
kalle Yes 2019-09-12 15:04
kelunik Yes 2019-09-12 21:48
keyur Yes 2019-09-14 01:57
kguest Yes 2019-09-23 13:31
klaussilveira Yes 2019-09-12 15:26
krakjoe Yes 2019-09-12 23:29
laruence Yes 2019-09-26 06:25
lcobucci Yes 2019-09-13 22:53
levim Yes 2019-09-12 13:56
malukenho Yes 2019-09-24 15:07
marandall Yes 2019-09-14 21:36
mcmic Yes 2019-09-17 07:46
mrook Yes 2019-09-23 08:37
narf Yes 2019-09-17 05:23
nikic Yes 2019-09-12 12:03
ocramius Yes 2019-09-12 12:14
pajoye Yes 2019-09-23 15:08
patrickallaert Yes 2019-09-24 15:38
petk Yes 2019-09-15 11:49
pmmaga Yes 2019-09-24 10:18
ralphschindler Yes 2019-09-19 21:09
ramsey Yes 2019-09-15 20:44
rasmus Yes 2019-09-13 00:00
reywob Yes 2019-09-12 12:43
salathe No 2019-09-12 15:06
santiagolizardo Yes 2019-09-12 22:17
sebastian Yes 2019-09-12 12:25
sergey Yes 2019-09-12 12:19
stas No 2019-09-12 16:56
svpernova09 Yes 2019-09-12 12:50
till Yes 2019-09-23 16:12
trowski Yes 2019-09-12 14:15
wyrihaximus Yes 2019-09-18 20:09

Discussions on the mailing list

[RFC] Reclassifying engine warnings
by Nikita Popov · 137 messages
[VOTE] Reclassifying engine warnings
by Nikita Popov · 27 messages
fdiv() function
by Nikita Popov · 2 messages
Allowing variable strings to be defined for a string offset
by George Peter Banyard · 4 messages
[RFC] Userspace operator overloading
· 1 message
Long-Term Planning for PHP 9.0 Error Promotion
by Mark Randall · 1 message
Revisiting RFC: Engine Warnings -- Undefined array index
by Dan Liebner · 27 messages

RFC text

Copied from wiki.php.net, last synchronized Oct 13, 2026 11:51 UTC

Introduction

While newly introduced error conditions in the engine typically use Error exceptions, we have many old error conditions that use inappropriate severity levels for historical reasons. For example, accessing an undefined variable, while being a very severe programming error, only generates a notice. This RFC proposes to reevaluate existing error conditions and reclassify their severity level as appropriate.

Proposal

General Guidelines

As we don't have any existing rules on the matter, here are some general guidelines I try to follow in the following reclassification:

  • Error exceptions should be the baseline for error conditions that indicate a programming error.
  • If there is an expectation that a certain error condition is commonly intentionally suppressed, especially in legacy code, an exception should not be used.
  • If the error condition is data-dependent, it may be preferable not to use an exception.
  • For error conditions that have known false positives, a notice should be used.
  • Avoid promoting from notice directly to Error exception. I'm only proposing this for the case of undefined variables, because it is so severely misclassified right now.

Proposed Classification

The following table contains a list of errors with notice or warning severity generated in the engine, excluding warnings that are generated by functions which have an optimized opcode implementation.

The table shows both the current error level, as well as the proposed level. A rationale for the proposed change (or non-change) is provided below each group of errors.

The “undefined variable”, “undefined array index” and “division by zero” error conditions are discussed separately below, because they are more controversial.

Message Current Level Proposed Level
Attempt to increment/decrement property '%s' of non-object Warning Error exception
Attempt to modify property '%s' of non-object Warning Error exception
Attempt to assign property '%s' of non-object Warning Error exception
Creating default object from empty value Warning Error exception
Rationale: These errors are generated when a property is accessed on a non-object inside a write context. If the non-object is “truthy” a warning is generated and the operation is ignored, if it is “falsy” an empty stdClass object is created instead. While auto-vivification is a core part of the language for arrays, the same is not the case for objects, and creating a property on a non-object is almost certainly a programming error rather than an intentional action.
Trying to get property '%s' of non-object Notice Warning
Undefined property: %s::$%s Notice Warning
Rationale: The first warning is for the same case as above, but for read contexts. This is classified as a warning, because it usually indicates a programming error (in modern code, all non-magic properties tend to be known and fixed). However, object properties can also be dynamic (e.g. JSON in object form), in which case accessing an undefined property may be a less severe issue. Generally, PHP is somewhat lenient with read accesses to “missing” data.
Cannot add element to the array as the next element is already occupied Warning Error exception
Rationale: This error condition occurs when trying to push to an array for which the PHP_INT_MAX key is already used. This error condition practically never occurs outside of specially crafted code, and implies data loss if it does. As such, it is changed into an exception.
Cannot unset offset in a non-array variable Warning Error exception
Cannot use a scalar value as an array Warning Error exception
Trying to access array offset on value of type %s Notice Warning
Rationale: These diagnostics are generated when trying to use scalars as arrays. The first two occur in write contexts, the latter in read contexts. The latter was introduced in PHP 7.4 as a notice with express intention to elevate the severity in PHP 8.0. In line with the symmetrical case on objects, the write case is treated more severely here, as it usually implies data loss.
Only arrays and Traversables can be unpacked Warning TypeError exception
Invalid argument supplied for foreach() Warning TypeError exception
Rationale: These are simple type errors and should be treated as such.
Illegal offset type Warning TypeError exception
Illegal offset type in isset or empty Warning TypeError exception
Illegal offset type in unset Warning TypeError exception
Rationale: These are generated if an array or object is used as an array key. Once again this is a simple type error.
Indirect modification of overloaded element of %s has no effect Notice (Notice)
Indirect modification of overloaded property %s::$%s has no effect Notice (Notice)
Rationale: These notices occur if __get() or offsetGet() return a non-reference, but are used in a write context. Because our detection of write context has false positives right now, these should remain notices until we can be sure that the diagnostic is always legitimate.
Object of class %s could not be converted to int/float/number Notice (Notice)
Rationale: Comparison between objects and scalars currently works by casting the object to the appropriate type, which is why comparisons like $obj == 1 will currently also throw this notice, while they should not. Until this issue is resolved, the classification as notice should remain.
A non-numeric value encountered Warning (Warning)
A non well formed numeric value encountered Notice (Notice)
Rationale: The difference between these two warnings is whether a string is completely non-numeric, or whether it has a numeric prefix. This is a runtime issue based on the specific string value involved in an operation, which may be user-controlled. For this reason we don't promote to exceptions.
Accessing static property %s::$%s as non static Notice (Notice)
Rationale: This notice is somewhat confusing in what it does: It is thrown when accessing $obj->staticProp but does not actually read the static property. Instead it will fall back to using the dynamic property named staticProp. There is more inconsistency in this area, in that accessing a protected static property on the object will generate an Error exception, even though it would not actually access that property. I'm not sure what to do here, but would be inclined to just leave it alone.
Array to string conversion Notice Warning
Rationale: This is generally a bug (and the “Array” string you get is meaningless), but in many cases also not a particularly severe one. Since string conversion exceptions are supported now, we could also promote this to an Error exception, and I'm generally open to that.
Resource ID#%d used as offset, casting to integer (%d) Notice Warning
Rationale: This is in principle a meaningful operation, but exotic enough that intent should be indicated with an explicit integer cast.
String offset cast occurred Notice Warning
Illegal string offset '%s' Warning (Warning)
Rationale: The former is thrown when using null/bool/float as a string offset, the latter if the string is not integral. Both of these should use the same severity.
Uninitialized string offset: %d Notice Warning
Illegal string offset: %d Warning (Warning)
Rationale: The former is used when reading an out-of-bounds string offset, the latter when writing to an out-of-bounds negative string offset (for positive offsets, the string is extended instead). In line with undefined index/property, we consistently generate a warning here.
Cannot assign an empty string to a string offset Warning Error exception
Rationale: This operation is not meaningful and indicates some kind of logic error.
Only variables should be passed by reference Notice (Notice)
Only variable references should be returned by reference Notice (Notice)
Only variable references should be yielded by reference Notice (Notice)
Only variables should be assigned by reference Notice (Notice)
Attempting to set reference to non referenceable value Notice (Notice)
Cannot pass by-reference argument %d of %s%s%s() by unpacking a Traversable, passing by-value instead Warning (Warning)
Rationale: The use of values where a reference is expected is currently somewhat inconsistent, with everything from compiler errors, Error exceptions, warnings and notices being possible depending on the specific case. Passing a non-variable to a reference argument is often a programming error, because it will not be possible to modify the passed value and the reference cannot serve its purpose. However, this is complicated by optional reference arguments or return values that are optionally references. In both cases the warning may be a false positive. It's not really clear what to do here, so I'm retaining the current classification for now.

Undefined variable

In most cases, accessing an undefined variable is a severe programming error. The current low classification is a legacy from the Dark Ages of PHP, where features like register_globals made conditionally defined variables more typical, and code quality standards were lower.

Ideally, undefined variables should be compile errors, but as the dynamic nature of PHP precludes a reliable compile-time analysis, this RFC proposes to generate an Error exception instead.

However, throwing an exception may complicate the upgrading of legacy code that currently suppresses the generation of notices wholesale, as the issue can no longer be ignored. Some people have even suggested that the use of undefined variables is a legitimate coding style choice.

For this reason, a separate vote will decide whether we should throw an Error exception, generate a warning or keep the current notice.

Undefined array index

Similarly to undefined variables or an undefined object properties, reading an undefined array index/key would generally be considered a programming error in modern PHP code. However, while variables and object properties are predominantly statically known (i.e., when variable variables and dynamic object properties are not used), the same is not true to array keys, which tend to be dynamic.

Some languages, such as JavaScript, do not consider accesses to undefined array keys to be an error condition at all, and allow such an operation to be performed silently. While it is not predominant in the PHP world, some people subscribe to such a coding style also for PHP code, and as such would prefer undefined array key access to remain an easily suppressible notice.

A separate vote will decide whether to elevate undefined array offset/index conditions to a warning, or leave them as notices.

Division by zero

Division by zero currently has somewhat inconsistent behavior. The % operator throws a DivisionByZeroError. However, the / throws a “Division by zero” warning and returns one of +Inf, -Inf or NaN, following IEEE 754 semantics.

The rationale for this behavioral discrepancy is as follows: The % operator works on integers. As such the conjugated operation is actually not /, but rather intdiv(), which does throw DivisionByZeroError. An integer operation shouldn't return a floating point number, so throwing an Error exception is the only choice here.

Not throwing an Error exception for division by zero using / is motivated by the fact that such division does have a well-defined result under IEEE 754. In some areas of application (such as numerics) it may be useful to not treat division by zero as an error condition at all, though such applications are unusual for PHP. Similarly, Bob Weinand argued that for reporting code that makes heavy use of divisions, it may be preferable to have the ability to suppress this error condition.

On the other hand, the current behavior, and especially the discrepancy with % is quite unexpected, and many people expect that a division by zero error will in fact generate a DivisionByZeroError (duh). This discussion has already come up multiple times on the internals list and in pull requests.

As I think that both sides have a reasonable argument here, there will be a separate vote on whether to change the division by zero behavior.

Backward Incompatible Changes

Conversion of notices to warnings is fairly harmless, because both continue execution after the diagnostic has been generated. Conversion to exceptions implies that the current control flow will be aborted.

This may impact code that makes very liberal use of the error suppression operator @ or disables error reporting wholesale. The proposal does try to avoid changing notices that are more likely to be suppressed into exceptions.

If desired, an error handler can be provided that filters out the error conditions that will be turned into an exception, so that projects can focus on addressing them prior to an upgrade.

Vote

All the following votes are independent. Each requires a 2/3 majority and may pass/fail independent of other votes. Voting closes 2019-09-26.

As the “undefined variable” vote is a 3-way vote, acceptance is determined as follows: “Error exception” is accepted if it has 2/3 majority. Otherwise, “Warning” is accepted if the first two options together have 2/3 majority. Otherwise, “Keep Notice” applies.

Vote: Change undefined variable severity to? — Error exception: 36 · Warning: 18 · Keep Notice: 10 (closed)

.

Vote: Change undefined array index severity to? — Warning: 42 · Keep Notice: 21 (closed)

.

Vote: Change division by zero severity to? — DivisionByZeroError exception: 52 · Keep Warning: 8 (closed)

.

Vote: Accept remaining classifications shown in the table above? — Yes: 54 · No: 3 (closed)

Changelog

  • 2019-09-12: Split out undefined index/offset into a separate section.
  • 2019-09-10: Keep current classification for reference errors.
  • 2019-08-28: Split off the “undefined variable” case into a separate vote, as it was a major point of contention on-list.