Content with Style

Web Technique

buggy behaviour of parent:: in PHP 5.3.3

by Matthias Willerich on December 18, 18:26

So, this app I hadn't been looking at in a few months did not work at all. I traced the bug down to a method that itself called a parent method. The parent only contains __call and __callStatic methods, and for some reason __callStatic was called, although the class it was called from was an object instance.

To isolate the case I used the code example provided in the PHP manual, extended it and ooo'd and ahh'd at the result.

<?php
class MethodTest {
    public function __call($name, $arguments) {
        // Note: value of $name is case sensitive.
        echo "Calling object method '$name' "
             . implode(', ', $arguments). "\n";
    }
    
    public static function __callStatic($name, $arguments) {
        // Note: value of $name is case sensitive.
        echo "Calling static method '$name' "
             . implode(', ', $arguments). "\n";
    }
}

class MethodTestExtended extends MethodTest {
    public function runExtendedTest($var){
        parent::runTest($var);
    }
}

$obj = new MethodTest;
$obj->runTest('in object context');
//Calling object method 'runTest' in object context
MethodTest::runTest('in static context');
//Calling static method 'runTest' in static context

$obj = new MethodTestExtended;
$obj->runTest('in object context');
//Calling object method 'runTest' in object context
MethodTestExtended::runTest('in static context');
//Calling static method 'runTest' in static context

$obj = new MethodTestExtended;
$obj->runExtendedTest('in object context');
// PHP 5.3.3: Calling object method 'runTest' in static context
// __callStatic is called, and $this is not available.
// PHP 5.3.4: Calling object method 'runTest' in object context
// __call is called, and $this is available.
MethodTestExtended::runExtendedTest('in static context');
//Calling static method 'runTest' in static context, with a 
//Strict Standards warning, though (as the method isn't declared static)

The call is always routed via __callStatic, when called from within the extending class, regardless if it's in a static or object context, but not so when called directly.

Not believing my eyes, I started searching more creatively, and found that I was not the only one complaining about it; and luckily the right people thought so, too.

It so turns out that this behaviour was introduced in PHP 5.3.3, as part of another bug dealing with the opposite desired behaviour (calling class methods statically when in an object context), and removed again in PHP 5.3.4, smelling a little bit like a bug. A simple sudo port upgrade php5 did the job, bumping my install up to 5.3.4, and everything worked as intended. Yay!