有什么方法可以检查方法是被静态调用还是在实例化对象上调用?
尝试以下操作:
class Foo {
function bar() {
$static = !(isset($this) && $this instanceof self);
}
}
“从 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'] == '::';
}
}
检查
$this
是否已设置并不总是有效。
如果从对象内调用静态方法,则
$this
将被设置为调用者上下文。如果您真的想要这些信息,我想您必须从debug_backtrace
中挖掘出来。但为什么你首先需要它呢?您很可能可以以某种方式更改代码结构,这样您就不会这样做。
我实际上在我的所有脚本上使用了这行代码,它运行良好并且可以防止错误。
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
将解决这个问题,并避免与可能实现“半静态”功能的类发生冲突。
测试
$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"
测试 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() 的方法...
这是一个老问题,但我会添加一个替代答案。
有两个神奇的方法
__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”
检查是否定义了
$this
<?
class A {
function test() {
echo isset($this)?'not static':'static'; }
}
$a = new A();
$a->test();
A::test();
?>
编辑:击败它。
现在是 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();
当然还有其他技巧。
创建一个静态变量并在构造函数中更改它。
private static $isInstance = false;
public function __construct()
{
self::$isInstance = true;
}
现在可以查看了
public function myMethod()
{
if (self::$isInstance) {
// do things
}
}
只需在函数中将类作为新的返回即可。
return new self();