DEV Community

Sarfraz Ahmed
Sarfraz Ahmed

Posted on • Originally published at codeinphp.github.io on

Late Static Binding in PHP

Let's jump into an example up front to understand the concept. Let's create two classes parent and child which would tell us the name of the object using getName() method:

class Animal {
    protected $name = 'Animal';

    public function getName() {
        return $this->name;
    }
}
Enter fullscreen mode Exit fullscreen mode

Let's extend the Animal class so we can use its getName() method without repeating it in child class. We will only need the $name variable in child class to get it's name:

class Cat extends Animal {
    protected $name = 'Cat';
}
Enter fullscreen mode Exit fullscreen mode

Now we expect to get names of each object, let's do so:

$animal = new Animal;
$cat = new Cat;

echo $animal->getName(); // Animal
echo $cat->getName(); // Cat
Enter fullscreen mode Exit fullscreen mode

And we successfully get Animal and Cat echoed out. But now let's modify code a bit so that we can use those classes without creating their instances with the help of static keyword (eg global state):

class Animal {
    protected static $name = 'Animal';

    public static function getName() {
        return self::$name;
    }
}

class Cat extends Animal {
    protected static $name = 'Cat';
}

echo Animal::getName(); // Animal
echo Cat::getName(); // Animal
Enter fullscreen mode Exit fullscreen mode

Noticed the problem ? We wanted to see Animal and Cat to be echoed out like previous example but in both cases it said Animal not Cat.

The reason why in previous example things worked the way expected is because we explicitly created new instances of both classes using new keyword and PHP knew which class and method to use. This is not the case in second static example. In the second example, we are using the self keyword which always resolves to current class where it is called. This is reason why the name for the Cat class wasn't echoed out.

So how do we get the name of cat ? Here are few ways.

By Repeating Same Code In Child Class

class Animal {
    protected static $name = 'Animal';

    public static function getName() {
        return self::$name;
    }
}

class Cat extends Animal {
    protected static $name = 'Cat';

    public static function getName() {
        return self::$name;
    }    
}

echo Animal::getName(); // Animal
echo Cat::getName(); // Cat
Enter fullscreen mode Exit fullscreen mode

This works but it defeats the purpose of inheritance. What is the point of extending Animal class when we need to repeat same code in child class ? This isn't ideal.

By Using get_called_class()

class Animal {
    protected static $name = 'Animal';

    public static function getName() {
        $class = get_called_class();
        return $class::$name;
    }
}

class Cat extends Animal {
    protected static $name = 'Cat';
}

echo Animal::getName(); // Animal
echo Cat::getName(); // Cat
Enter fullscreen mode Exit fullscreen mode

This is better and works for our purpose.

By Using static keyword

PHP 5.3 introduced the static keyword to help deal with this issue. Before that, get_called_class() was what was used. Let's get the expected result using static keyword:

class Animal {
    protected static $name = 'Animal';

    public static function getName() {
        return static::$name;
    }
}

class Cat extends Animal {
    protected static $name = 'Cat';
}

echo Animal::getName(); // Animal
echo Cat::getName(); // Cat
Enter fullscreen mode Exit fullscreen mode

And this works fine too. These days using static keyword seems to be common practice instead of get_called_class() to deal with this issue though get_called_class() has many other uses too.


So in simple words, late static binding is something that helps us correctly resolve to static classes at run time. So when we use self keyword, PHP checks it at compile time which class to bind the method call to but when we use static keyword, PHP would check it late eg it would determine which class to use and bind method call to at runtime. Doing it at runtime is what helps PHP determine which class was meant.

Top comments (0)