views:

197

answers:

4

I've got an Abstract PHP superclass, which contains code that needs to know which subclass its running under.

class Foo {
    static function _get_class_name() {
        return get_called_class();
        //works in PHP 5.3.*, but not in PHP 5.2.*
    }

    static function other_code() {
        //needs to know
        echo self::_get_class_name();
    }
}

class Bar extends Foo {
}

class FooBar extends Foo {
}

Bar::other_code(); // i need 'Bar'
FooBar::other_code(); // i need 'FooBar'

This would work if I called the function get_called_class() -- however, this code is going to be run in PHP version 5.2.*, so that function is not available.

There's some custom PHP implementations of get_called_class() out there, but they all rely on going thru the debug_backtrack(), parsing a file name & line number, and running a regex on it to find the class name. This code needs to be able to be run on the fly, ie. not from a .php file. (It needs to work from a php -a shell, or an eval() statement.)

Ideally, a solution would work without requiring any code to be added to the subclasses… The only potential solution I can see though is adding the following code to each subclass, which is obviously a disgusting hack:

class FooBar extends Foo {
    static function _get_class_name() {
        return 'FooBar';
    }
}

EDIT: Wait, this doesn't even seem to work. It would've been my last resort. Can anybody think of something similar to this solution that'd get me the required functionality. Ie., I'm willing to accept a solution that requires me to add one function or variable to each subclass telling it what its class name is. Unfortunately, it seems that calling self::_get_class_name() from the superclass calls the parent class' implementation, even if the subclass has overridden it.

+1  A: 

This is not possible.

The concept of "called class" was introduced in PHP 5.3. This information was not tracked in previous versions.

As an ugly work-around, you could possibly use debug_backtrace to look into the call stack, but it's equivalent. For instance, in PHP 5.3, using ClassName::method() doesn't forward the static call; you have no way to tell this with debug_backtrace. Also, debug_backtrace is relatively slow.

Artefacto
debug_backtrace, though, lists the class as the superclass instead of the subclass. It lists the file and line number where it's being called, so I could theoretically go in there and regex the line to find the called class, assuming it was called with a Bar:: format, but that's not really a solution. And it wouldn't work in the context of a shell where the file name is stupidly listed as 'php shell code'
Kenneth Ballenegger
@Ken Yes, `debug_backtrace` sucks. Unfortunately, your only remaining options are 1) upgrade, 2) replace the static method `other_code` (`_get_class_name` won't do, because calling it from a `other_code` implementation in the superclass would result in the superclass's version always being called) in every subclass.
Artefacto
A: 

I have asked a question like this before, because I wanted a parent to have a factory method that was something like this

public static function factory() {
    return new __CLASS__;
}

But it always returned the parent class, not the inherited one.

I was told that it is not possible without late static binding. It was introduced in PHP 5.3. You can read the documentation.

alex
A: 

While you haven't shared your exact problem domain here, wanting this kind of thing is usually indicative of a disconnect between your object hierarchy and reality. Why not just put the functionality that needs to be specialized in a specialized subclass?

DDaviesBrackett
A: 

The solution is:

get_class($this);

However, I don't know if this sentence works in static functions. Give it a try and tell me your feedback.

robregonm
this doesn't work on static functions, unfortunately…
Kenneth Ballenegger