开发者

How do I check in PHP that I'm in a static context (or not)?

Is there any way I can check 开发者_StackOverflow社区if a method is being called statically or on an instantiated object?


Try the following:

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

Source: seancoates.com via Google


"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'] == '::';
    }
}


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.


I actually use this line of code on all my scripts,it works well and it prevents errors.

class B{
      private $a=1;
      private static $static=2;

      function semi_static_function(){//remember,don't declare it static
        if(isset($this) && $this instanceof B)
               return $this->a;
        else 
             return self::$static;
      }
}

The use of instanceof is not paranoia:

If class A call class B statically function $this may exist on the A scope; I know it's pretty messed up but php does it.

instanceof will fix that and will avoid conflicting with classes that may implement your "semi-static" functions.


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"


Testing isset($this) wasn't working for me, as mentioned by troelskn "$this will be set as the callers context."

abstract class parent
{
    function bar()
    {
        if( isset( $this ) ) do_something();
        else static::static_bar();
    }

    function static static_bar()
    {
        do_something_in_static_context();
    }
}

class child extends parent
{
    ...
}

$foo = new child();
$foo->bar(); //results in do_something()
child::bar(); //also results in do_something()

In my case, I have a parent class with a object and static context function that performs the same task within a child class. isset( $this ) was always returning true, however, I noticed that while $this switches between being class child in object context and calling(?) class on static context, the wonderful __class__ magic constant, remained as class parent!

Shortly there-after finding the function is_a, we can now test if we're in static context:

if(  is_a($this, __CLASS__) ) ...

Returns true on object context, false on static context.

Please test for your own implementations, as I'm only testing this for my specific scenario (a unique case of inheritance calling) in 5.3.

Unfortunately (for my case) I am yet unable to find a way to call the static_bar() since $this and static are referring to a separate class, and __class__ is referring to the parent class. What I need is a way to call child::static_bar()...


This is an old question, but I'll add an alternative answer.

There are two magic methods

__call($name, $arguments)
is triggered when invoking inaccessible methods in an object context.

__callStatic($name, $arguments)
is triggered when invoking inaccessible methods in a static context.

<?php
class MethodTest
{
    public function __call($name, $arguments)
    {
        // Note: value of $name is case sensitive.
        echo "Calling object method '$name' "
             . implode(', ', $arguments). "\n";
    }

    /**  As of PHP 5.3.0  */
    public static function __callStatic($name, $arguments)
    {
        // Note: value of $name is case sensitive.
        echo "Calling static method '$name' "
             . implode(', ', $arguments). "\n";
    }
}

$obj = new MethodTest;
$obj->runTest('in object context');

MethodTest::runTest('in static context');  // As of PHP 5.3.0

Outputs

Calling object method 'runTest' in object context
Calling static method 'runTest' in static context


Check whether $this is defined


<?

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

}

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

Edit: beaten to it.


It's 2022 now, with php 7.4, 8: you can/should no longer be vague about the context a method will be called in.

If a method is not declared static, 7.4 will warn you, 8 will fatal error.

If a method is declared static, $this is never available.

<?php

class C {
   public function nonStaticMethod() {
      print isset($this) ? "instance ": "static\n";
   }
   public static function staticMethod() {
      print isset($this) ? "instance ": "static\n";
   }
}

// php 8: Fatal error: Uncaught Error: Non-static method Foo::bar() cannot be called statically
// php 7.4: Deprecated: Non-static method Foo::bar() should not be called statically
C::nonStaticMethod();

C::staticMethod();

$f = new C();
$f->nonStaticMethod();
// `$this` is still not defined. It works without the instance context,
// even though you called it from an instance.
$f->staticMethod();

Other hacks are available, of course.


Create a static variable and change it in the constructor.

private static $isInstance = false;

public function __construct()
{
    self::$isInstance = true;
}

Now you can check it

public function myMethod()
{
    if (self::$isInstance) {
        // do things
    }
}


Just return the class as new within the function.

return new self();
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜