September 2006


Up until a few weeks ago, I had used PHP only a handful of times, generally when tinkering with WordPress. That was up until I started my current job, maintaining a terrible content management “system” written in a mixture of PHP and perl.

What kicked this client from “suck” to “kill me now” was having to deal with PHP. I hate this language. So. Much. The office can tell when I’m working on this project from the stream of profanity alone.

The current version of my “Why PHP is destroying my soul little by little” list:

  • You can’t write something like get_active_subscription($user)->subscription_type. You first have to assign the return value of get_active_subscription() to an intermediate variable, then grab the subscription_type attribute from that intermediate. The same thing goes for array subscription.

  • PHP’s three billion functions were named by someone on psychotropic drugs. As evidence: count v strlen v count_chars v str_word_count. Quick — what’s the difference?

  • $some_object->nonexistant_attribute evaluates to the empty string.

  • $misspelled_variable evaluates to the empty string.

  • Pushing a value on to an array is spelled $arr[] = $object. You’re right, that is better than a function (perl’s push @array, $object) or a method (python’s list.append(object)).

  • The incredibly consistent naming scheme for functions. My favorite examples are the array_* and *_array functions.

  • My absolute favorite comes from the PHP manual, talking about why you shouldn’t use barewords to index an array, i.e., $foo[bar] instead of $foo["bar"]:

    [Using a bareword] is wrong, but it works. Then, why is it wrong? The reason is that this code has an undefined constant (bar) rather than a string. and PHP may in future define constants which, unfortunately for your code, have the same name. It works because PHP automatically converts a bare string (an unquoted string which does not correspond to any known symbol) into a string which contains the bare string. For instance, if there is no defined constant named bar, then PHP will substitute in the string ‘bar’ and use that.

    Brilliant.

  • You can use return outside of functions without PHP complaining.

  • The entire array() class. Everything about it. Absolutely everything. I’ve been using it for a month, and I still don’t feel comfortable with the thing’s semantics.

  • From the docs for array_diff(): “Two elements are considered equal if and only if (string) $elem1 === (string) $elem2. In words: when the string representation is the same.”

    Best. Equivalence test. Ever.

  • Writing $a = $b || $c gives you a boolean, not the value of $b or $c like some more useful languages I can think of.

I’m still debating what conclusion to draw about PHP. I can’t decide whether it’s the diseased creation of a bunch of retards gone off their meds, or if it’s one of the most successful and widespread practical jokes ever conceived (”Let’s see how many people we can get to use this piece of shit!” “Dude, that’s awesome!”).

Following up on an earlier post, I’ve just submitted a trio of patches for Python’s unittest module to SourceForge:

  • Patch #1550272 is the test suite itself. It comprises 128 tests for the mission-critical parts of unittest.

  • Patch #1550273 fixes 6 issues uncovered while writing the test suite. Several other items that I raised earlier were judged to be either non-issues or behaviours that, while suboptimal, people have come to rely on.

  • Patch #1550263 follows up on an earlier patch I submitted for unittest’s docs. This new patch corrects and clarifies numerous sections of the module’s documentation.

I’m hopeful that these changes will make it into Python 2.5-final or 2.5.1 at the latest.

Here’s a list of the issues I uncovered while writing the test suite:

  1. TestLoader.loadTestsFromName() failed to return a suite when resolving a name to a callable that returns a TestCase instance.

  2. Fix a bug in both TestSuite.addTest() and TestSuite.addTests() concerning a lack of input checking on the input test case(s)/suite(s).

  3. Fix a bug in both TestLoader.loadTestsFromName() and TestLoader.loadTestsFromNames() that had ValueError being raised instead of TypeError. The problem occured when the given name resolved to a callable and the callable returned something of the wrong type.

  4. When a name resolves to a method on a TestCase
    subclass, TestLoader.loadTestsFromName() did not return
    a suite as promised.

  5. TestLoader.loadTestsFromName() would raise a ValueError (rather than a TypeError) if a name resolved to an invalid object. This has been fixed so that a TypeError is raised.

  6. TestResult.shouldStop was being initialised to 0 in TestResult.__init__. Since this attribute is always used in a boolean context, it’s better to use the False
    spelling.