[RndTbl] PHP undefined vars / array indices

Trevor Cordes trevor at tecnopolis.ca
Sat Jan 8 03:34:01 CST 2022


Any PHP coders out there?

So PHP really did it in 8.0: They really made accessing undefined vars
*and* array indices a full warning rather than a notice.  I had written in
past newsletters that I hoped this didn't mean what it sounded like it
meant.

But it does.

They really did it.

https://wiki.php.net/rfc/engine_warnings

I finally had to face the music with the upgraded MUUG server which now
uses PHP8.  It was coming for me in Fedora 25 anyhow (maybe 4 more months
to postpone that change).  The MUUG server is about 80% code that Allan
Pollard wrote (thanks Allan!) and 20% my own code.  Neither wrote
according to PHP8's magic new requirements.

Anyone here who does PHP and hasn't treated it as a typed / declared
language, because it is not one, is in for a great deal of pain when they
are forced to upgrade to PHP 8.  I'm not sure I've ever come across
existing PHP code where the dev treated it as a language where you must
pre-declare everything.  Of course, such people must exist, as exhibited
by the voting record for this PHP RFC.  Perhaps they are people who only
recently took up PHP and/or are coming from stricter languages.

And that is my main beef: if you want a strict language, use a strict
language.  Why take a loose language, which has always been loose and is
loose by design, and suddenly make a major change that is going to spew
out errors all over everyone's screen (if display_errors is on) for 90% of
all legacy code?  If I want strict variable declaration, I'll use one of
the zillion languages that force you, and even do nice compile-time checks
for you.

And you just know that while, at the moment, this change is limited to
making it a warning, the tyrants are itching to make this a full explosion
error. You can see it in the voting ("Change undefined variable severity
to?": vote 36 to 28).  Luckily for us PHP requires a 2/3 majority to pass
an RFC.

To "fix" these errors in code, you can in most cases use a lot of tricks,
like massive use of ?? everywhere.  But that makes the code look really
ugly and I start to question why?  And if you use list() to capture
results of a function which can return variable type of variable length
arrays, you're really in trouble as there's no current syntax to combine
?? or isset() with that.

Sure, you can go in and turn your PHP into C by pre-declaring every
variable, if you can spot them all in complex functions or global scope
code.  But that only helps you with the "undefined variables" thing, not
the "undefined array index" thing.  The latter is far more insidious
because your index can be a variable itself!  So for that case you must
always use isset() or ?? or some other trick.

I could go into more examples of what I had to do to the MUUG code if
anyone is interested.

So what can you do in the real world?  The first thing you do is turn off
display_errors, which is probably off on production boxes anyhow (but
wasn't on "hobby" boxes like MUUG, but it is now).  Then make sure those
warnings are being logged.  Then sit back and let people use your site and
wait for the MBs of log lines saying undefined this and that.

Then you have a choice: a) ignore it all and set your logrotate to a
short period of time so you don't fill your log disks; or b) fix every
error that shows up.  I did (b) on MUUG and it's not fun, and that's just
a small code base.  In either case you must pray the PHP tyrants don't
soon vote this into a runtime exception error, as when you retrofit your
old code you're almost never going to find every instance of this.

Compare this situation with perl strict.  Perl introduced "strict" mode
with "use strict" a long time ago.  That makes you my() every variable and
its dog or you get a full blown error.  But I'm pretty sure it doesn't
affect array indices.  In any event, if you don't agree with the perl
devs, you just write "no strict" (or just disable this specific strict).
No tyrrany.  Freedom and choice.  Perl, like PHP has never been strictly
typed or declared.  Perl will never force you to use strict.  Never.  So
why is PHP?

PHP could have made it a configurable option.  It would be really easy.
But they didn't.

I have some projects with over 100k lines of PHP code.  The simple fact
that "fixing" this will make my code look extremely ugly, harder to read,
less maintainable, and probably more prone to bugs is all the reason I
need to decide that I will never "fix" my code.  Not to mention it will be
probably 20k lines of code that need to be "fixed", and it's a pointless
pursuit because in the end I'll never find them all.  (grep -P '\[' ... ya
right.)

So it will be log & ignore, or not log at all (though I still will need to
see legit warnings somehow); or git clone php and change 2 lines of code
and maintain my own version forever.  In fact, it may be time to do a fork
of PHP: sane-php or something.

Lastly, I'm willing to debate the philosophical points, especially using
the RFC's wording as a basis; however, I'm not sure anyone is interested
in taking the other side (please, hardcore PHP programmers only).  I'll
leave you with the arrogant wording from the RFC:

	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.
	[...]
	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.

"Legacy", "Dark Ages" indeed.  Nice framing.  "Legitimate coding style
choice."  How gracious.


More information about the Roundtable mailing list