如何在 PHP 中检查我是否处于静态上下文中?

问题描述 投票:0回答:12

有什么方法可以检查方法是被静态调用还是在实例化对象上调用?

php methods static
12个回答
66
投票

尝试以下操作:

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

11
投票

“从 debug_backtrace() 中挖掘它”并不是太多工作。 debug_backtrace() 有一个“type”成员,如果调用是静态的,则为“::”;如果不是静态的,则为“->”。所以:

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


8
投票

检查

$this
是否已设置并不总是有效。

如果从对象内调用静态方法,则

$this
将被设置为调用者上下文。如果您真的想要这些信息,我想您必须从
debug_backtrace
中挖掘出来。但为什么你首先需要它呢?您很可能可以以某种方式更改代码结构,这样您就不会这样做。


6
投票

我实际上在我的所有脚本上使用了这行代码,它运行良好并且可以防止错误。

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;
      }
}

instanceof的使用并非偏执:

如果A类静态调用B类函数,则

$this
可能存在于A范围内; 我知道这很混乱,但 php 可以做到。

instanceof
将解决这个问题,并避免与可能实现“半静态”功能的类发生冲突。


4
投票

测试

$this

class Foo {

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

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

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

编辑: 正如 pygorex1 指出的那样,您还可以强制要静态评估的方法:

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"

3
投票

测试 isset($this) 对我来说不起作用,正如 troelskn 提到的“$this 将被设置为调用者上下文。”

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()

就我而言,我有一个带有对象和静态上下文函数的父类,该函数在子类中执行相同的任务。 isset( $this ) 总是返回 true,但是,我注意到,虽然 $this 在对象上下文中的类子级和静态上下文中的调用(?) 类之间切换,但奇妙的

__class__
魔法常量仍然是类父级!

找到函数 is_a 后不久,我们现在可以测试是否处于静态上下文中:

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

在对象上下文中返回 true,在静态上下文中返回 false。

请测试您自己的实现,因为我仅针对 5.3 中的特定场景(继承调用的独特情况)进行测试。

不幸的是(对于我的情况)我还无法找到调用

static_bar()
的方法,因为 $this 和 static 指的是一个单独的类,而
__class__
指的是父类。我需要的是一种调用 child::static_bar() 的方法...


3
投票

这是一个老问题,但我会添加一个替代答案。

有两个神奇的方法

__call($name, $arguments)

在对象上下文中调用不可访问的方法时会触发。

__callStatic($name, $arguments)

在静态上下文中调用不可访问的方法时会触发。

<?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

输出

在对象上下文中调用对象方法“runTest”
在静态上下文中调用静态方法“runTest”


1
投票

检查是否定义了

$this


1
投票
<?

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

}

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

编辑:击败它。


1
投票

现在是 2022 年,PHP 7.4、8:您可以/不应该再对调用方法的上下文含糊不清。

如果一个方法没有声明为静态,7.4 会警告你,8 会出现致命错误。

如果方法被声明为静态,则

$this
永远不可用。

<?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();

当然还有其他技巧。


0
投票

创建一个静态变量并在构造函数中更改它。

private static $isInstance = false;

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

现在可以查看了

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

-1
投票

只需在函数中将类作为新的返回即可。

return new self();
© www.soinside.com 2019 - 2024. All rights reserved.