在类中调用静态方法?

196

如何在同一类内的另一个方法中调用静态方法?

$this->staticMethod();
或者
$this::staticMethod();

13
您可能会对这个(self vs. $this)感兴趣:https://dev59.com/DXVC5IYBdhLWcg3w51hv - Felix Kling
1
只是提醒一下,你的第一个例子是实例变量调用静态方法,这是不可能的,因为静态方法是类的一部分,不能通过实例变量访问。 - joejoeson
现在可以删除 $this 了,因为如果只使用静态方法且不存在实例,则它不起作用。 - malhal
真不可思议,找这个问题和答案有多难。这是因为PHP没有将它们称为“类方法”或“类函数”。翻白眼 - Otheus
5个回答

391

1
...但是为什么?$this->staticMethod() 也可以工作。您能解释一下为什么 self::staticMethod() 更正确吗(如果确实如此)? - Ian Dunn
34
简单来说,只有在实例化对象时 $this 才存在,你只能在已经存在的对象内使用 $this->method。如果没有对象而只是调用一个静态方法,并且在该方法中你想调用同一类中的另一个静态方法,你必须使用 self::。因此,为避免潜在的错误(和严格警告),最好使用 self - jeroen
1
谢谢!在 Laravel 中,我发现我无意中使用 $this 调用了扩展控制器中的静态方法,但问题直到代码推送到 stage 才浮出水面。没有错误返回,值只是 0。要小心处理这个问题,应该使用 self:: - blamb

48

假设这是您的班级:

class Test
{
    private $baz = 1;

    public function foo() { ... }

    public function bar() 
    {
        printf("baz = %d\n", $this->baz);
    }

    public static function staticMethod() { echo "static method\n"; }
}

foo() 方法内部,让我们看一下不同的选项:

$this->staticMethod();

那么调用staticMethod()会被视为实例方法,对吗?不是这样的。这是因为该方法声明为public static,解释器将其视为静态方法进行调用,因此它将按预期工作。可以认为这样做使代码中发生静态方法调用的事实不太明显。

$this::staticMethod();

自 PHP 5.3 版本起,您可以使用 $var::method() 来表示 <class-of-$var>::; 这相当方便,尽管上述用例仍然相当不寻常。 因此,我们来介绍一下调用静态方法的最常见方式:

self::staticMethod();

现在,在你开始认为::静态调用运算符之前,让我给你举另一个例子:

self::bar();

这将打印出baz = 1,这意味着$this->bar()self::bar()执行的是完全相同的操作;这是因为::只是一个作用域解析运算符。它存在的原因是为了使parent::self::static::起作用,并让您访问静态变量;方法的调用方式取决于其签名以及调用者的调用方式。

要在实际操作中看到所有这些内容,请查看此3v4l.org输出


self::bar() 看起来有些误导 - 现在是否已经被弃用了?(使用 self:: 调用实例方法而不是静态方法)。 - ToolmakerSteve
@ToolmakerSteve,您觉得它以何种方式具有误导性? - Ja͢ck
从逻辑上讲,在调用静态方法时不存在 self。根据定义:静态方法可从任何地方调用,并且不接收“self”参数。尽管如此,我认为 php 语法很方便,这样您就不必编写 MyClassName::。我习惯于静态类型的语言,其中编译器必须给出当前范围内所有可用变量,因此可以省略 (相当于) self::。所以只需说 self instanceMethod;没有理由说 self staticMethod - ToolmakerSteve

20

这是一个很晚的回复,但在之前的回答中补充了一些细节。

当涉及从同一类的另一个静态方法中调用PHP静态方法时,区分self和类名非常重要。

以这段代码为例:

class static_test_class {
    public static function test() {
        echo "Original class\n";
    }

    public static function run($use_self) {
        if($use_self) {
            self::test();
        } else {
            $class = get_called_class();
            $class::test(); 
        }
    }
}

class extended_static_test_class extends static_test_class {
    public static function test() {
        echo "Extended class\n";
    }
}

extended_static_test_class::run(true);
extended_static_test_class::run(false);

这段代码的输出结果为:

原始类

扩展类

这是因为self指的是代码所在的类,而不是调用它的类。

如果你想使用继承原始类的方法,你需要使用类似以下代码:

$class = get_called_class();
$class::function_name(); 

2
我觉得这篇文章很有启发性。有一个小问题,我不认为其他答案是“误导性的”。更准确地说,它们是“不完整的”,它们没有回答(未被问到的)问题:在静态方法A调用另一个静态方法B的情况下,如果B已经在子类中被重写了,那么self::会做什么?依我之见,在静态级别上要谨慎使用方法覆盖;将其限制在实例方法上看起来会更清晰。换句话说,你代码的读者期望实例方法被覆盖(这就是面向对象编程的本质),但不期望静态方法被覆盖。 - ToolmakerSteve
1
非常有帮助,很容易理解一个类的扩展不是原始类。因此,在这种情况下不使用self是合理的。您已经声明了一个作为第一个类扩展的单独类。在扩展类中使用self将引用扩展类。这并不与其他答案相矛盾,但它确实有助于说明self的范围。 - iyrin

2

在较新的PHP版本中,self::staticMethod();也将不起作用。它会抛出严格标准错误。

在这种情况下,我们可以创建相同类的对象并通过对象调用。

以下是示例:

class Foo {

    public function fun1() {
        echo 'non-static';   
    }

    public static function fun2() {
        echo (new self)->fun1();
    }
}

1
可以这样做,但是如果fun1没有使用self,那么将其作为实例方法并不合理。在php中正确的方法是声明public static function fun1,然后通过指定类来调用:Foo::fun1。我相信这是修复严格标准错误的预期方式。 - ToolmakerSteve

0
在类内调用静态方法 className::staticFunctionName 范例 ClassName::staticMethod();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接