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

Reply via email to