views:

190

answers:

6

Hello,

Is there any way I can check if a method is being called statically or on an instantiated object?

Jamie

+2  A: 

Check whether $this is defined

K Prime
+5  A: 

Test for $this:

class Foo {

    function bar() {
        if (isset($this)) {
            echo "Y";
        } else {
            echo "N";
        }
    }
}

$f = new Foo();
$f->bar(); // prints "Y"

Foo::bar(); // prints "N"

Edit: As pygorex1 points out, you can also force the method to be evaluated statically:

class Foo {

    static function bar() {
        if (isset($this)) {
            echo "Y";
        } else {
            echo "N";
        }
    }
}

$f = new Foo();
$f->bar(); // prints "N", not "Y"!

Foo::bar(); // prints "N"
Boldewyn
+1 Interesting note: try changing `function bar()` to `static function bar()` - in this case `$f->bar()`, `Foo::bar()` and `$f::bar()` are all called in static context.
pygorex1
Cool. I always thought it would raise an exception or so, if you'd try and call a static method from an instance. Thanks for pointing this out.
Boldewyn
+1  A: 
<?

class A {
    function test() {
            echo isset($this)?'not static':'static';                                }

}

$a = new A();
$a->test();
A::test();
?>

Edit: beaten to it.

Bill Zeller
+10  A: 

Try the following:

class Foo {
   function bar() {
      $static = !(isset($this) && get_class($this) == __CLASS__);
   }
}

Source: seancoates.com via Google

BenTheDesigner
That's fairly paranoid.. but nice one nonetheless
K Prime
mmm ... this doesn't work, if i have a class 'baz' extending 'foo' and calling function 'bar' from baz' context, because \_\_CLASS\_\_ is still 'foo' and get_class($this) is 'baz'.
harald
+1  A: 

Checking if $this is set won't work always.

If you call a static method from within an object, then $this will be set as the callers context. If you really want the information, I think you'll have to dig it out of debug_backtrace. But why would you need that in the first place? Chances are you could change the structure of your code in a way so that you don't.

troelskn
I forgot about that small annoyance. Interesting.
strager
Wouldn't BenTheDesigner's attempt tackle this issue?
Boldewyn
As long as `$this` isn't an instance of `Foo`, but I guess that's a bit contrived. Still, having to ask the question in the first place is a red flag to me.
troelskn
A: 

"Digging it out of debug_backtrace()" isn't too much work. debug_backtrace() had a 'type' member that is '::' if a call is static, and '->' if it is not. So:

class MyClass {
    public function doStuff() {
        if (self::_isStatic()) {
            // Do it in static context
        } else {
            // Do it in object context
        }
    }

    // This method needs to be declared static because it may be called
    // in static context.
    private static function _isStatic() {
        $backtrace = debug_backtrace();

        // The 0th call is to _isStatic(), so we need to check the next
        // call down the stack.
        return $backtrace[1]['type'] == '::';
    }
}

Chris Hoffman