簡體   English   中英

使用雙冒號 (::) 調用非靜態方法

[英]Calling non-static method with double-colon(::)

為什么我不能使用具有方法 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

PHP靜態和非靜態方法非常松散。 有一件事我沒有看到這里要注意的是,如果你調用一個非靜態方法, ns從類的非靜態方法中靜態C$this里面ns將把您的實例C

class A 
{
    public function test()
    {
        echo $this->name;
    }
}

class C 
{
     public function q()
     {
         $this->name = 'hello';
         A::test();
     }
}

$c = new C;
$c->q();// prints hello

如果您要嚴格報告錯誤,則實際上是某種錯誤,但不是這樣。

這是PHP的一個“怪癖”。 這是設計使然,以防止向后傳播,以弄清一段時間之前我們是否實際實例化了一個對象(請記住,PHP是解釋的,不是編譯的)。 但是,如果未實例化對象,則通過via范圍解析運算符訪問任何非靜態成員將發出致命錯誤。

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

這是PHP 4向后兼容。 在PHP 4中,對象方法和以靜態類方法編寫的全局函數之間沒有區別。 因此,兩者都奏效了。

但是,隨着PHP 5對象模型的更改-http: //php.net/oop5-引入了static關鍵字。

然后從PHP 5.1.3開始,您會收到有關以下內容的適當的嚴格標准警告:

嚴格標准:非靜態方法Foo :: bar()不應靜態調用

和/或:

嚴格標准:非靜態方法Foo :: bar()不應靜態調用,假設$ this來自不兼容的上下文

您應該為開發設置啟用的功能。 因此,這只是向后兼容,因為在這種情況下,語言不會有太大差異,因此在運行時已對其進行了“定義”。

現在,您已經可以在代碼中定義它了,但是如果您仍然稱其為“錯誤”,則代碼不會中斷。

一些演示可以觸發錯誤消息並顯示不同PHP版本上已更改的行為:http: //3v4l.org/8WRQH

PHP 4沒有靜態關鍵字(在函數聲明上下文中),但仍允許使用::靜態調用方法。 為了向后兼容,在PHP 5中繼續這樣做。

您可以執行此操作,但是如果在名為fun1()的函數中使用$this ,則代碼將出錯

警告在PHP 7中,不建議靜態調用非靜態方法,它將生成E_DEPRECATED警告。 將來可能會刪除對靜態調用非靜態方法的支持。

鏈接

在大多數語言中,您將需要一個類的實例才能執行實例方法。 當您使用范圍解析運算符調用實例方法時,PHP似乎會創建一個臨時實例。

不知道為什么PHP允許這樣做,但是您不想養成這樣做的習慣。 您的示例僅起作用,因為它不會嘗試訪問該類的非靜態屬性。

像這樣簡單:

<?php
class Foo {

    private $color;

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

Foo::bar();

會導致致命錯誤

我注意到,如果您從類內部調用非靜態方法self :: test(),則不會發出嚴格標准的警告,就像您調用Class :: test()一樣。 我相信這與LSB沒有關系,因為我的課程沒有擴展(在php 5.5上測試)?

靜態和非靜態調用相同方法的一種方法是使用魔術方法__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();

流利的數學課

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

如果您想了解該類的工作原理,請查看:

從 PHP8 開始,這不再有效。

靜態調用非靜態方法的能力最終在 PHP 8 中移除

靜態調用非靜態方法的能力已被移除。 因此is_callable()在檢查具有類名的非靜態方法時將失敗(必須檢查對象實例)。

它最初在 PHP 7 上棄用

對未聲明為靜態的方法的靜態調用已被棄用,將來可能會被刪除。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM