[英]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 類(下面的代碼)是一個示例,您可以在其中靜態調用add
或subtract
方法,也可以不調用:
$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()
在檢查具有類名的非靜態方法時將失敗(必須檢查對象實例)。
對未聲明為靜態的方法的靜態調用已被棄用,將來可能會被刪除。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.