PHP late static binding

Being PHP an interpreted language, we don't need to compile our programs ourselves. However, that doesn't mean it is never complied. The PHP interpreter compiles and runs it for us so there is still these two phases: compile time and run time. Static properties get their values on run time.

Eh... Static?

A class property or method declared as static makes them accessible without needing an instantiation of the class. They belong to the class, rather than the object that instantiates it.

Late Static Binding

I recently discovered a PHP feature with which I wasn't familiar. It is called late state binding and it is used 'to reference the called class in a context of static inheritance'. This means, for example, that if you need to access a static method from an inherited class, you need to use the keyword static, rather than self.

What's wrong with 'self::'

Nothing is wrong with self but it has its limitations, a static reference to the current class with self, is resolved using the class in which the function belongs. That way if a class extends another with a static method, a call to self will return the parent class' static method, instead of the child's.

Example

While investigating how this works, I've come across tutorials and articles providing abstract examples to show how late static binding works, but not how one actually uses it. I've to say that when I see code examples with an abstract 'Vehicle' class, that is extended by 'Car' and 'Motorbike' or something of the kind, I stop reading. With this example, I'd like to provide a real world example of how to use late static binding. The example, though, is fabricated and the problem could be modelled without the need to use a static method, but we will be looking at an educational code example with a real-world application.

The code below, contains an implementation of a data file parser. We would like to be able to parse text files with .csv or .tsv format.

<?php

abstract class DataFileParser
{
    abstract public static function getFieldDelimiter();
    
    public function parseFile($path, $headers = false)
    {
        $fileHandler = fopen($path, "r");
        $delimiter = static::getFieldDelimiter();

        if ($headers)
        {
            $headersLine = fgets($fileHandler);
            $fieldHeaders = explode($delimiter, $headersLine);
        }

        $returnArray = [];
        while (!feof($fileHandler))
        {
            $line = fgets($fileHandler);
            $row = explode($delimiter, $line);

            if ($headers)
            {
                $returnArray[] = array_combine($fieldHeaders, $row);
            }
            else
            {
                $returnArray[] = $row;
            }
        }

        fclose($fileHandler);

        return $returnArray;
    }
}

class CsvFileParser extends DataFileParser
{
    public static function getFieldDelimiter()
    {
        return ",";
    }
}


class TsvFileParser extends DataFileParser
{
    public static function getFieldDelimiter()
    {
        return "\t";
    }
}

This code, contains the abstract class DateFileParser with the abstract method getFieldDelimiter, which will return the caracter delimiting each field in a row of data within the file. The other two classes CsvFileParser and TsvFileParser need to implement the getFieldDelimiter method to provide the delimiter character.

Then, the method parseFile performs the parsing, calling the former method on line 10.

$delimiter = static::getFieldDelimiter();

In this line, the class that 'static' represents is either CsvFileParser or TsvFileParser, depending on which one is calling the method. These classes don't need to redefine the parseFile method, as they will be correctly calling their own getFieldDelimiter thanks to the use of static::

Conclusion

This article doesn't intend to be an exhaustive explanation of late static binding or the uses of the static keyword in php. It is rather to provide a believable example of its use, simple enough to be easily understood but real enough not to sound ridiculous. The example could be modelled without using a static method or could use the fgetcsv php function.