Late Static Bindings in PHP Callbacks

No idea if this is ever useful, but just found this not documented in the PHP manual so far (and the Callbacks entry looks already chaotic so I don’t edit it right now):

You can write callbacks of static class methods as a string in the form of "classname::methodname". This should be commonly known, an example of that is:

// http://3v4l.org/vdhJq

echo Module::work('hello world'), "\n";              # HELLO WORLD
echo call_user_func('Module::work', 'hello world');  # HELLO WORLD

abstract class Module
{
    public static function work($it) {
        return strtoupper($it);
    }
}

What I stumbled over and which I didn’t know is that since PHP 5.3 it is also possible to reference the current class with three additional strings for the classname placeholder above:

  1. "self::methodname" – use the current class.
  2. "parent::methodname" – use the parent class.
  3. "static::methodname" – use the class that was initially called at runtime.

Here an example that uses a callback function inside the module class to do some string replacements with the "static" string:

// http://3v4l.org/SsaZg

echo Module::work('hello world.'), "\n";  # [[[hello]]] [[[world]]].
echo MyModule::work('hello world.');      # {{{hello}}} {{{world}}}.

abstract class Module
{
    public static function work($it) {
		return preg_replace_callback('~\w+~', 'static::replace', $it);
    }

    protected static function replace($matches) {
        return sprintf('[[[%s]]]', $matches[0]);
    }
}

abstract class MyModule extends Module
{
    protected static function replace($matches) {
        return sprintf('{{{%s}}}', $matches[0]);
    }

}

Sidenote: The array callback notation works for that as well:

    preg_replace_callback('~\w+~', array('static', 'replace'), $it);

This came a bit unexpected to me because in another feature introduced in PHP 5.3: A call of static class methods with a variable for the classname PHP:

// http://3v4l.org/IWQtr

echo Module::work('hello world'), "\n";  # HELLO WORLD

abstract class Module
{
    public static function work($it) {
        $module = 'Module';
        return $module::strtoupper($it);
    }

    private static function strtoupper($it) {
		return strtoupper($it);
    }

}

Unexpected because it does not allow to use the strings "self", "parent" or "static" inside that variable:

// http://3v4l.org/p0RQv

echo Module::work('hello world'), "\n";  # Fatal error: Class 'self' not found

abstract class Module
{
    public static function work($it) {
        $module = 'self';
        return $module::strtoupper($it);
    }

    private static function strtoupper($it) {
		return strtoupper($it);
    }

}

Last but not least, there is this very special callback, I don’t have any name for. What it does is working exactly like the "self::methodname" callback:

    
    preg_replace_callback('~\w+~', array('self',   'self::replace'),   $it);
                                         // like self - http://3v4l.org/B6Lbe

    preg_replace_callback('~\w+~', array('static', 'static::replace'), $it);
                                       // like static - http://3v4l.org/adTgD

    preg_replace_callback('~\w+~', array('static', 'self::replace'),   $it);
                                       // like static - http://3v4l.org/GaCVT

    preg_replace_callback('~\w+~', array('self',   'static::replace'), $it);
    // like "final" (invalid callback in LSB context) - http://3v4l.org/oBeNN

So much for the magic static and self-self life in callbacks and class method calls. PHP is not well known for language consistency and I put that one as well into the book. One should not exploit this static feature anyway and a module class should be abstract final probably but sadly, PHP does not know that.

This post is just another write-up for the know-your-language department and not a recommendation at all.


Edit: Parts of my first conclusion on self-self were wrong, it does not do any LSB, what I thought was LSB was in the first static::replace example was wrong. I also made that example more distinct.

This entry was posted in PHP Development, Pressed, The Know Your Language Department and tagged , , , , , , , , , , , . Bookmark the permalink.

One Response to Late Static Bindings in PHP Callbacks

  1. askapache says:

    Very interesting read, diving into some of this myself (though not that deep). Can’t wait to test some more of this out.. If only everyone was >= 5.3

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s