用双冒号调用非静态方法(::)

时间:2010-09-20 19:24:05

标签: php static

为什么我不能使用静态方法(class :: method)的非静态方法?这是某种配置问题吗?

class Teste {

    public function fun1() {
        echo 'fun1';
    }
    public static function fun2() {
        echo "static fun2" ;
    }
}

Teste::fun1(); // why?
Teste::fun2(); //ok - is a static method

10 个答案:

答案 0 :(得分:30)

PHP在静态与非静态方法上非常松散。我在这里没有注意到的一件事是,如果你在ns的非静态方法中静态地调用非静态方法C$this在{{1}内将引用您的ns

实例
C

如果你有严格的错误报告,这实际上是某种错误,但不是。

答案 1 :(得分:24)

这是PHP的一个着名的“怪癖”。设计是为了防止反向传播,以便在不久前我们实际实例化一个对象(记住,PHP是解释的,不是编译的)。但是,如果未实例化对象,则访问任何非静态成员via scope resolution运算符将发出致命错误。

由PHP.net提供:     

class User {
    const GIVEN = 1;  // class constants can't be labeled static nor assigned visibility
    public $a=2;
    public static $b=3;

    public function me(){
        echo "print me";
    }
     public static function you() {
        echo "print you";
    }
}

class myUser extends User {
}

// Are properties and methods instantiated to an object of a class, & are they accessible?
//$object1= new User();        // uncomment this line with each of the following lines individually
//echo $object1->GIVEN . "</br>";        // yields nothing
//echo $object1->GIVE . "</br>";        //  deliberately misnamed, still yields nothing
//echo $object1->User::GIVEN . "</br>";    // yields nothing
//echo $object1->a . "</br>";        // yields 2
//echo $object1->b . "</br>";        // yields nothing
//echo $object1->me() . "</br>";        // yields print me
//echo $object1->you() . "</br>";        // yields print you

// Are  properties and methods instantiated to an object of a child class,  & are accessible?
//$object2= new myUser();        // uncomment this line with each of the following lines individually
//echo $object2->GIVEN . "</br>";        // yields nothing
//echo $object2->a . "</br>";        // yields 2
//echo $object2->b . "</br>";        // yields nothing
//echo $object2->me() . "</br>";        // yields print me
//echo $object2->you() . "</br>";        // yields print you

// Are the properties and methods accessible directly in the class?
//echo User::GIVEN . "</br>";        // yields 1
//echo User::$a . "</br>";            // yields fatal error since it is not static
//echo User::$b . "</br>";            // yields 3
//echo User::me() . "</br>";        // yields print me
//echo User::you() . "</br>";        // yields print you

// Are the properties and methods copied to the child class and are they accessible?
//echo myUser::GIVEN . "</br>";        // yields 1
//echo myUser::$a . "</br>";        // yields fatal error since it is not static
//echo myUser::$b . "</br>";        // yields 3
//echo myUser::me() . "</br>";        // yields print me
//echo myUser::you() . "</br>";        // yields print you
?>

答案 2 :(得分:14)

这是PHP 4向后兼容性。在PHP 4中,对象方法和作为静态类方法编写的全局函数之间没有区别。因此两者都有效。

然而,随着PHP 5对象模型的变化 - http://php.net/oop5 - 引入了静态关键字。

然后从PHP 5.1.3开始,您会得到关于以下内容的严格标准警告:

  

严格标准:不应静态调用非静态方法Foo :: bar()

和/或:

  

严格标准:非静态方法Foo :: bar()不应该静态调用,假设来自不兼容的上下文的$ this

您应该已为您的开发设置启用了它。所以它只是向后兼容到语言不能足够差异的时间,所以这是在运行时“定义”的。

现在您可以在代码中定义它,但是如果您仍然将其称为“错误”,则代码不会中断。

一些Demo触发错误消息并显示不同PHP版本的更改行为:http://3v4l.org/8WRQH

答案 3 :(得分:13)

PHP 4没有静态关键字(在函数声明上下文中),但仍然允许使用::静态调用方法。为了向后兼容的目的,这在PHP 5中继续。

答案 4 :(得分:6)

您可以执行此操作,但如果您在名为$this

的函数中使用fun1(),则代码会出错

答案 5 :(得分:6)

警告 在PHP 7中,不推荐静态调用非静态方法,并将生成E_DEPRECATED警告。将来可能会删除对静态调用非静态方法的支持。

Link

答案 6 :(得分:1)

在大多数语言中,您需要拥有该类的实例才能执行实例方法。当您使用范围解析运算符调用实例方法时,PHP似乎会创建一个临时实例。

答案 7 :(得分:1)

不确定为什么PHP允许这样做,但你不想养成这样做的习惯。您的示例只能起作用,因为它不会尝试访问该类的非静态属性。

简单的事情:

<?php
class Foo {

    private $color;

    public function bar() {
        echo 'before';
        $this->color = "blue";
        echo 'after';
    }
}

Foo::bar();

会导致致命错误

答案 8 :(得分:0)

我注意到如果从类中调用非静态方法self :: test(),则不会发出严格标准的警告,就像调用Class :: test()时一样。我相信这与LSB无关,因为我的课程没有扩展(在PHP 5.5上测试过)?

答案 9 :(得分:0)

静态和非静态调用相同方法的一种方法是使用魔术方法 __call__callStatic

FluentMath 类(下面的代码)是一个示例,您可以在其中静态调用方法 addsubtract

$res1 = FluentMath::add(5)    // add method called statically
    ->add(3)                  // add method called non-statically
    ->subtract(2)
    ->result();

$res2 = FluentMath::subtract(1)->add(10)->result();

FluentMath 课程

class FluentMath
{
    private $result = 0;

    public function __call($method, $args)
    {
        return $this->call($method, $args);
    }

    public static function __callStatic($method, $args)
    {
        return (new static())->call($method, $args);
    }

    private function call($method, $args)
    {
        if (! method_exists($this , '_' . $method)) {
            throw new Exception('Call undefined method ' . $method);
        }

        return $this->{'_' . $method}(...$args);
    }

    private function _add($num)
    {
        $this->result += $num;

        return $this;
    }

    private function _subtract($num)
    {
        $this->result -= $num;

        return $this;
    }

    public function result()
    {
        return $this->result;
    }
}

如果您想了解该类的工作原理,请查看: