Coder Perfect

Why are abstract static class methods not allowed in PHP 5.2+?

Problem

After activating strict warnings in PHP 5.2, I noticed a slew of stringent standards warnings in a project that had previously been written without them:

The function in question is abstract static and belongs to the abstract parent class Program. It should be implemented in its child classes, such as TVProgram.

I did come with few references to the change here:

My question is: can someone explain in a clear way why there shouldn’t be an abstract static function in PHP?

Asked by Artem Russakovskii

Solution #1

It’s a lengthy, depressing tale.

Late static bindings were not yet in the language when PHP 5.2 originally introduced this warning. If you’re unfamiliar with late static bindings, keep in mind that the following code does not operate as you may expect:

<?php

abstract class ParentClass {
    static function foo() {
        echo "I'm gonna do bar()";
        self::bar();
    }

    abstract static function bar();
}

class ChildClass extends ParentClass {
    static function bar() {
        echo "Hello, World!";
    }
}

ChildClass::foo();

Aside from the strict mode warning, the code above isn’t functional. Even when foo() is called as a ChildClass method, the self::bar() call in foo() corresponds to the bar() method of ParentClass. If you try to run this code with strict mode off, you’ll see “PHP Fatal error: Cannot call abstract method ParentClass::bar()”.

Because of this, PHP 5.2’s abstract static methods were useless. The whole point of utilizing an abstract method is that you can write code that calls it without knowing which implementation it’ll call, and then give alternative implementations on different child classes. This usage of abstract static methods is not possible in PHP 5.2 since there is no clean way to design a method of a parent class that calls a static method of the child class on which it is called. As a result, any use of abstract static in PHP 5.2 is incorrect code, most likely due to a misunderstanding of the self keyword’s functionality. It was perfectly acceptable to issue a warning in this case.

However, PHP 5.3 adds the ability to use the static keyword to refer to the class on which a method was called (unlike the self keyword, which always refers to the class in which the method was defined). It works perfectly in PHP 5.3 and higher if you change self::bar() to static::bar() in my example above. More on self vs. static may be found in New self vs. new static.

The clear rationale for having abstract static throw a warning was gone with the addition of the static keyword. Late static bindings’ main purpose was to allow methods defined in a parent class to call static methods that would be defined in child classes; allowing abstract static methods seems reasonable and consistent given the existence late static bindings.

Something that you don’t want to make public. Because ParentClass is abstract, it can’t be instantiated, therefore its instance methods can’t be called. Using a non-static class – that is, making all the methods instance methods and making the children of ParentClass all be singletons or something – would fix this problem. This argument is weak in my opinion (since I believe that exposing ParentClass::foo() isn’t a major concern and that using singletons instead of static classes is often overly verbose and unattractive), but you may fairly disagree – it’s a somewhat subjective judgment.

So the PHP developers maintained the warning in the language because of this argument, right?

Uh, not exactly.

The warning should be removed, according to PHP bug report 53081, because the addition of the static::foo() construct made abstract static functions logical and helpful. Rasmus Lerdorf (the author of PHP) begins by labeling the request as fraudulent, then proceeds to defend the warning with a long chain of faulty reasoning. Finally, this conversation took place:

Rasmus’ claim that his example code “functions properly” is untrue; as you know, it raises a strict mode warning. He was probably testing without strict mode enabled. Regardless, a perplexed Rasmus incorrectly closed the request as “bogus.”

fying justification – You presumably came here trying to find some kind of rationale for the warning. Unfortunately, in the actual world, decisions are occasionally made based on commonplace errors and faulty reasoning rather than rational decision-making. This is just one of such instances.

Fortunately, as part of PHP RFC: Reclassify E STRICT warnings, the illustrious Nikita Popov has removed the warning from the language in PHP 7. Finally, sanity has won out, and once PHP 7 is published, we’ll be able to utilize abstract static without getting this annoying warning.

Answered by Mark Amery

Solution #2

The class that declared the static methods is the one that owns them. You may build a static method with the same name when extending the class, but you are not actually implementing a static abstract function.

The same is true for adding static methods to any class. You are not actually overriding the superclass’s static method if you extend that class and create a static method with the identical signature.

REVISION (Sept. 16th, 2009) This has been updated. Abstract static is back in PHP 5.3, for better or worse. (For further information, see http://php.net/lsb)

ADDITIONAL INFORMATION (by philfreo) In PHP 5.3, abstract static is still not allowed; LSB is similar but not the same.

Answered by Jonathan Fingland

Solution #3

This problem can be solved in a very basic way that actually makes sense from a design standpoint. As Jonathan put it:

As a workaround, you might perform the following:

<?php
abstract class MyFoo implements iMyFoo {

    public static final function factory($type, $someData) {
        // don't forget checking and do whatever else you would
        // like to do inside a factory method
        $class = get_called_class()."_".$type;
        $inst = $class::getInstance($someData);
        return $inst;
    }
}


interface iMyFoo {
    static function factory($type, $someData);
    static function getInstance();
    function getSomeData();
}
?>

And now you enforce that any class subclassing MyFoo implements a getInstance static method, and a public getSomeData method. Even if you don’t subclass MyFoo, you can use iMyFoo to construct a class that does similarly.

Answered by Wouter van Vliet

Solution #4

I realize this is an old post, however….

Why not just throw an exception in that parent class’s static function, such that the exception is thrown even if you don’t override it?

Answered by Petah

Solution #5

An abstract class/interface, in my opinion, can be viewed as a contract between programmers. It focuses on how things should look and behave rather than implementing actual functionality. It’s not a natural law that forbids php developers from doing it, as seen in php5.0 and 5.1.x, but the desire to follow other OO design patterns in other languages. If one is already familiar with other languages, these approaches essentially strive to prevent unexpected behavior.

Answered by merkuro

Post is based on https://stackoverflow.com/questions/999066/why-does-php-5-2-disallow-abstract-static-class-methods