On Tue, Mar 29, 2022 at 9:44 PM Rowan Tommins <rowan.coll...@gmail.com> wrote: > > Hi all, > > If $foo is not defined, statements such as $foo += 1 and $foo .= 'blah' > raise "undefined variable" Warnings in PHP 8, and will throw Errors in > PHP 9. However, the very similar looking $foo[] = 1 succeeds silently. > > This seems odd to me, as "append to string" and "append to array" seem > like very similar operations, with most of the same use cases and > possible bugs. > > > From an *implementation* point of view, this is presumably because they > are defined as different Op Codes - ASSIGN_OP for .= and ASSIGN_DIM for > []=, I believe. But that doesn't explain *why* ASSIGN_DIM behaves this way. > > A *historical* explanation might relate to Perl's "autovivification" > feature. However, PHP does *not* implement the same rules as Perl: for > instance, Perl will create array dimensions just by reading them, which > PHP does not; and Perl has a completely different type system, with > cases like "a scalar becomes a reference to a hash unless already a > reference to a list". Note also that I'm *not* talking about > multi-dimensional arrays with missing keys here, only undefined local > variables, as were the subject of the recent RFC. > > The *observable behaviour* for most operators in PHP is the same: > > 1) if the variable is undefined, consider the value to be null > 2) coerce the value to the appropriate type; if the value is null, this > gives the relevant "empty" value, such as '', 0, or [] > 3) apply the operator > > There isn't anything particularly special with $foo[] = 'bar' in this > case, except that it's the only operator that doesn't raise a Warning > (and planned Error) at step 1. The same goes for all the other uses of > the [] syntax I can think of, like $foo['key'] = 'bar', or $ref =& $foo[]. > > > For example, consider the following simple validation code > [https://3v4l.org/pP5CU]: > > $requiredFields = ['name', 'age', 'hair_colour']; > > // Note: $errorString is not initialised > foreach ( $requiredFields as $field ) { > if ( ! isset($_POST[$field]) ) { > $errorString .= "Missing required field '$field'. "; > } > } > echo $errorString; > > This gives an "Undefined variable" Notice / Warning / Error, depending > on the version. That's reasonable, as failing to initialise $errorString > might cause problems if this code is integrated into a loop or larger > function later. > > However, switch the code from building up a string to building up an > array, and the result is identical, but the Notice / Warning / Error > goes away [https://3v4l.org/ojZ1O]: > > // Note: $errorArray is not initialised > foreach ( $requiredFields as $field ) { > if ( ! isset($_POST[$field]) ) { > $errorArray[] = "Missing required field '$field'. "; > } > } > echo implode('', $errorArray); > > > Can anyone give a compelling reason why we should keep this > inconsistency, or should I raise an RFC to bring it in line with other > undefined variable accesses? > > > Regards, > > -- > Rowan Tommins > [IMSoP] > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php >
I think it's worth raising an RFC. There are other inconsistencies as well now, depending on how the undefined variable comes to exist, particularly around arrays. For example: $x = null; $a = $x['nope']; echo $a; There should be an error here, but $a gets the value null and only a warning is issued. Yet, this is already an error: $x = new class { public string|null $nope; }; $a = $x->nope; echo $a; So, depending on how you json_decode() you may or may not have issues. -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php