6

Ok, so I've read lots of posts on here about this, but I think this is a specific and new question.

I want the functionality of what lots of us on here wrongly call an "abstract static method". That is: I want a class that insists classes that extend it implement certain static methods.

It seems there are two roads round the much discussed problem of not allowing abstract static, but both seem inelegant.

Problem

The following generates an error: "PHP Strict Standards: Static function A::fn() should not be abstract".

<?php
abstract class A
{
     abstract static public function fn();
}

class B extends A
{
    static public function fn()
    {
         // does something on class vars etc.
    }
}

Solution 1: use Interfaces

<?php
interface iA {
    static function fn();
}


abstract class A implements iA 
{
} // obviously this would have other stuff in it in reality

class B extends A
{
    static public function fn()
    {
         // does something on class vars etc.
    }
}

The problem with this is that an interface assumes (dictates) that all the methods be public. So while this achieves the goal of insisting that sub-classes of an abstract class have certain static methods, it can only be used for public methods; there is still no way to ensure subclasses of A implement a protected static method.

Protected static methods are useful when the method works entirely on static data but ought not to be called from 'outside'.

Solution 2: exceptions

abstract class A
{
     static public function fn()
     {  
         throw new Exception(get_called_class() . " must implement fn()");
     }

}

class B extends A
{
    static public function fn()
    {
         // does something on class vars etc.
    }
}

This works at runtime if fn() when called. But it's not useful to have to deal with coding syntax mistakes at runtime. And while this could be a hack for one method, it's a lot more code for each method.

Is there something so wrong with this design that the language rightly forbids it? Seems odd that there are various ways to insist subclasses provide most types of method, but not static ones.

Community
  • 1
  • 1
artfulrobot
  • 20,637
  • 11
  • 55
  • 81
  • the initial flaw is that these should not be static in the first place. All your described problems will go away and are easy to implement when you use objects. – Gordon Mar 06 '13 at 12:04
  • Yes, you can solve the problem of getting from A-B by going to C instead but then you're not at B. Class variables are very useful where the data is shared between all objects of that class. – artfulrobot Mar 06 '13 at 13:32
  • To me they are rather an indicator that there is an object waiting to be extracted. Check Flyweight Pattern and TypeObject/Powertype to see if they are better fit. – Gordon Mar 06 '13 at 13:45
  • Using those patterns does not solve the problem - flyweight because the shared data is not immutable ; type object because this cannot provide compile time validation. – artfulrobot Mar 06 '13 at 20:05

2 Answers2

2

It's because static methods belong to the class where they are defined. A::fn() and B::fn() are two different methods, regardless of the inheritance tree. So it makes little sense to define A::fn() as abstract.

Maybe your methods in question should not be abstract at all? If you want to use any kind of polymorphism, there should be objects involved.

Fabian Schmengler
  • 24,155
  • 9
  • 79
  • 111
  • I understand that the methods belong to the class, but `class C extends B {}; C::fn()` will call `B::fn()` if undefined in `C`. Question is how to enforce B to provide these static methods. – artfulrobot Feb 15 '13 at 13:15
  • you already explained *how*. I thought the question was *why not*? ;) – Fabian Schmengler Feb 15 '13 at 13:29
0

I might be totally wrong, but I have no problem in using

abstract class A
{
     abstract static public function fn();
}

class B extends A
{
    static public function fn()
    {
         print 1;
    }
}

B::fn();

It produces 1 as an output. I have run your code in here. What version of php do u use ?

greenLizard
  • 2,326
  • 5
  • 24
  • 30
  • 2
    PHP 5.3. You do not have E_STRICT enabled at compile time (i.e. don't set it in the code, it will be too late). Try editing your php.ini file and adding `error_reporting = E_ALL | E_STRICT` – artfulrobot Feb 15 '13 at 13:17