Sometimes bugs are in the eye of the beholder as a recent PHP bug report
illustrates. That report also illustrates how quickly discussions in bug
reports can spiral out of control, turning to anger and insults. There are
some comical aspects to the thread, but the underlying issue, maintaining
compatibility with existing bugs, is one that many projects struggle with.
A PHP user ("endosquid") reported that the
number_format() function had changed behavior in PHP 5.3; that is,
when number_format("",0) is called, it no longer returns "0",
instead it returns an empty string. Given that the first argument to the
function is supposed to be a number, in particular a floating point number
that is to be formatted based on the rest of the arguments, an empty string
might seem like the right thing to return. On the other hand, all earlier
versions of the function returned a string containing "0".
It turns out that part of the work that went into version 5.3 was to clean
up the parameter parsing code in PHP, and to use one routine,
zend_parse_parameters(), internally. As PHP creator
Rasmus Lerdorf related in the thread: "Most
of PHP was using this already, but there were still some stragglers
like number_format()." Lerdorf also suggested casting the
first argument to a float (i.e. number_format((float)"",0)) as a
solution to the problem.
As one would guess, endosquid's application wasn't calling
number_format() directly with an empty string, but was instead
passing a variable that may or may not have been initialized. In general
that is a bad programming practice, but it is quite common in
PHP code where the language has often tried to "do the right thing" with
uninitialized variables. But if the "right thing" changes, lots of code that
relied on it can break.
The argument that endosquid makes about what number_format()
should return is not entirely without merit. The function is supposed to
return a formatted number, and the empty string is hardly that, so
endosquid believes that it should return "0". But, as
Lerdorf points out, what would one expect number_format("a",0) to
return? The unfortunate answer is that pre-5.3 versions did return
"0" in that case. So, in tightening up the PHP parameter parsing code, a
substantial difference in the behavior of number_format() was
The documentation for number_format()
is not terribly helpful as it doesn't address error conditions at all. It
does specify that the first parameter is a float, but PHP will
happily take strings like "9" or "3.14159" for that parameter, converting
as needed. Given all
that, programmers have to rely on what the language actually does, and
since at least PHP 3, number_format() has always
returned "0" when handed random strings.
It doesn't take long for the bug report thread to descend into flames.
Evidently endosquid works in a tightly controlled environment that requires
a raft of paperwork to accompany code changes, but that still doesn't
justify a claim of "MONTHS [of] fixing code for no real
benefit". It seems clear that endosquid didn't quite understand who
it was responding to the bug report when asking Lerdorf to "escalate
this to someone who can answer the question as to why
this was changed". Lerdorf responds:
"Escalate? Oh how I wish I had someone to escalate to."
Lerdorf also explained that the change was first made public as part of the
first 5.3 release candidate in March 2009. He said that interested folks
had until July to make a case that any particular change shouldn't go into
the release. While endosquid complained that 5.3 had only recently become
available on the platform he was using, Lerdorf pointed out
that users have some responsibility to keep up with their tools:
of your responsibility in your position is to keep track of your tools
and the changes coming down the pipeline. 5.3 was available to you as
a release candidate in March of last year, and even earlier directly
from our revision control system. Many things have changed and there
are many many people out there affected by these changes, we recognize
that. That is also why we are not likely to reverse a change like this
that others in your situation have now accounted for, tested and
deployed in production for many months simply because it is
inconvenient for you.
There is certainly some truth to Lerdorf's admonishment, but it didn't sit
well with endosquid, who plans to change the C code back to the old
behavior. Patching the language source—rather than making a fairly
simple textual substitution to the number_format() call
sites—seems a bit extreme, but is evidently
easier in that environment. Unlike some proprietary alternatives, though,
free software allows just that kind of change.
But free software developers should not have to deal with insulting
comments from bug reporters. There are multiple alternatives for
endosquid, including staying with the 5.1.x version of PHP, patching the
5.3.x source, or fixing the actual calls, so getting angry and lashing out
in the bug report is not likely to help anyone. It is, as Lerdorf
points out, "a classic case of how not to treat unpaid volunteers who
critical pieces of your money-making infrastructure".
There is always the question, though, of when a "bug" has lived long enough
that it becomes something that needs to be carried forward. Once
applications start depending on buggy behavior, there will always be
annoyed users when the bug gets fixed. The Linux kernel has run into this
problem numerous times, generally opting to maintain the
"insanity" (in the words
of Al Viro) for compatibility's sake.
It is a difficult balance to strike. PHP developers cannot possibly know
all of the different corner-cases and quirks that PHP applications depend
on. When fixing what they see as a bug, they have to rely on users testing
betas and release candidates to find places where the "bug" label may not
be appropriate—or at least requires some discussion. But users are
often busy with other things, so we are likely to see this kind of
situation play out for various projects in the future.
to post comments)