On Wed, Aug 28, 2019 at 2:10 PM Nikita Popov <nikita....@gmail.com> wrote:

> On Wed, Aug 28, 2019 at 12:41 PM Zeev Suraski <z...@php.net> wrote:
>
>>
>>
>> On Wed, Aug 28, 2019 at 12:33 PM Nikita Popov <nikita....@gmail.com>
>> wrote:
>>
>>> Hi internals,
>>>
>>> I think it's time to take a look at our existing warnings & notices in
>>> the
>>> engine, and think about whether their current classification is still
>>> appropriate. Error conditions like "undefined variable" only generating a
>>> notice is really quite mind-boggling.
>>>
>>> I've prepared an RFC with some suggested classifications, though there's
>>> room for bikeshedding here...
>>>
>>> https://wiki.php.net/rfc/engine_warnings
>>
>>
>> Specifically on undefined variables, the way we deal with them has little
>> to do with register_globals.  It's behavior you can find in other
>> dynamic languages (e.g. Perl), and allows for certain code patterns (which
>> rely on the automatic creation of a variable whenever it's used in write
>> context, and on a default known-in-advance value in case it's used in a
>> read context).  It's fine not to like this behavior or the code patterns
>> that commonly rely on it (e.g., @$foo++), but it's intentional and isn't
>> related to any historical reasons.
>>
>
> This argument makes sense for arrays and objects (and I don't promote
> undefined index/property to exceptions for that reason), but I don't think
> it holds any water for simple variables. Writing @$counts[$key]++ is a lazy
> way to count values and avoid ugly boilerplate for if
> (isset($counts[$key])) { $counts[$key]++; } else { $counts[$key] = 1; }.
> But @$foo++ is just a really bad way of writing either $foo++ or $foo = 1.
> Outside of variable variables, the concept of a conditionally defined
> variable just doesn't make a lot of sense.
>

This example has nothing to do with arrays.  There are many code patterns
in which relying on this behavior makes perfect sense for folks who are a
lot less strictly-minded.  For example:

foreach (whatever) {
  if (sth) {
    @$whCount++;
  }
}

Yes, it may be painful for many eyes that $whCount is not explicitly
initialized, but the above code is perfectly legitimate, warning-free
notice-compliant code since forever.  Moreover - this isn't legacy - there
are a lot of folks who appreciate this precise behavior, which is
documented and works as expected for the last 20+ years.

Or:

if ($bookCount>0) {
  $suffix = 's';
}

print "$bookCount book$suffix";

These are just two simple cases I bumped into myself recently.  There's an
infinite supply of more of those where these came from.


>
>> I think many (if not all) of your proposals make sense, but most of them
>> make sense as an opt-in - perhaps using something similar to Perl's strict
>> mode (which incidentally, changes the way the language treats undefined
>> variables in exactly the same way).  This would also provide a future-proof
>> solution for additional similarly-themed proposals (such as strict ops,
>> etc.).
>>
>
> I don't think this is an appropriate use of an opt-in. It's a case where
> we can balance language cleanup with backwards compatibility concerns. Code
> that works after this proposal will also work before it, and as such there
> is no danger of ecosystem bifurcation that would need to be addressed by an
> opt-in.
>

Calling this 'cleanup' is opinionated, and avoiding bifurcation by forcing
that opinion on everyone isn't a very good solution for those who have
other opinions.  While the opinion that variables must not be used before
being initialized is obviously a valid one - it is just that, one valid
opinion - and there are others.  PHP never took this opinion as an
axiomatic requirement (and not because of register_globals) - instead, the
intent was to have a default value for uninitialized variables - a
consistent, documented behavior since the dawn of the language.  Can this
be problematic under certain situations?  Absolutely.  Can it be useful in
other cases?  Sure (which is why it's very common).  A great deal of folks
both rely on this behavior and *like *it.  Those who don't (and there's
plenty of those as well of course) - always had a reasonable solution of
enabling E_STRICT and enforcing E_STRICT-compliant code.  I still think
that having a strict mode (which can encompass strict types, strict ops,
stricter error behavior, etc.) makes a lot of sense and would arguably be a
superior option for the many folks who prefer a stricter language - but
there's simply no way we can change one of the most fundamental behaviors
of the language and force it down people's throats - not only because it
breaks compatibility, but because it breaks how many people are used to
write their PHP code.  Perl provided stricter-liking folks with a solution
in the form of 'use strict;' decades ago;  JS did something similar much
more recently.  Neither of these created any sort of bifurcation - it's a
simple, sensible solution that has virtually no downsides.

Zeev

Reply via email to