PHP中::、->、self、parent::、$this操作符的區別

來源:互聯網
上載者:User

標籤:des   style   http   color   java   使用   io   strong   

在訪問PHP類中的成員變數或方法時,如果被引用的變數或者方法被聲明成const(定義常量)或者static(聲明靜態),那麼就必須使用操作符::,反之如果被引用的變數或者方法沒有被聲明成const或者static,那麼就必須使用操作符->。

另外,如果從類的內部訪問const或者static變數或者方法,那麼就必須使用自引用的self,反之如果從類的內部訪問不為const或者static變數或者方法,那麼就必須使用自引用的$this。

 

靜態變數
是只存在於函數範圍的變數, 不過, 在函數執行完成後,這種變數的值不會丟失,也就是說, 在下一次調用這個函數時,變數仍然會記得原來的值. 要將某個變數定義為靜態, 只需要在變數前加上 static 關鍵字即可.

類中靜態元素的使用
在類中, static 關鍵字有兩種主要用法, 一是用來定義靜態成員,一是用來定義靜態方法. 在類的內部, 可以使用範圍限定符 (::) 來訪問不同層次範圍的變數.

靜態成員
靜態成員是一種類變數, 可以把它看成時屬於整個類而不是屬於類的某個執行個體. 與一般的執行個體變數不同的是, 靜態成員只保留一個變數值, 而這個變數值對所有的執行個體都是有效的, 也就是說, 所有的執行個體共用這個成員.
$this 只表示類的當前執行個體, 而 self:: 表示的是類本身,在類之外的代碼中不能使用這個操作符,而且它不能識別自己在繼承樹階層中的位置.
也就是說, 在擴充類中使用self 範圍時, self 可以調用基類中聲明的方法, 但它調用的總是已經在擴充類中重寫的方法. 與$this 不同的是, 在使用靜態變數時,必須在範圍限定符後面加上$符號.
在擴充類中, 在基類的方法被重寫的情況下,使用 parent 範圍調用定義在基類中的方法.靜態成員也可以只屬於父類. 如果在子類和父類中同時聲明了某個成員,也可以使用parant:: 在子類中訪問父類中的變數. 在這種情況下, 父類的靜態成員和子類的靜態成員儲存的是不同的值.
可以在 :: 操作符的左邊寫上類的名稱來靜態地訪問某個成員, 這樣避免建立類的執行個體. 不僅省略掉執行個體化類的代碼, 而且還會更高效, 因為類的每個執行個體都會佔用一小部分的系統資源.
在使用 :: 操作符訪問成員變數時, 需要再次注意對$符號的使用. 因為PHP當前不支援動態靜態變數的使用, 也就是說不支援可變的靜態變數. 在使用$this->$var時, 被訪問的成員是包含在$var中的變數的值. 而不用$符號訪問某個變數實際上尋找的是類的某個常量而常量是不能通過$this來訪問的.
PHP6 中提出的static:: 範圍使我們不再需要使用self:: 和parent::. 當希望指向最終的實現功能的類時, 就可以使用static::, 這個限定符會在代碼執行之前立即計算出繼承層次機構上最後那個類的成員. 之一過程被稱為延遲綁定, 它使我們可以在子類中重寫某個靜態變數, 並且也可以從某個在父類中聲明的函數中反問這個最終成員.

靜態方法
靜態方法和非靜態方法之間有一個重要的區別: 在調用靜態方法時, 不再需要擁有類的執行個體.
靜態方法和非靜態方法使用原則:
一是如果某個方法中不包含$this 變數, 就應該時靜態方法; 如果不需要類的執行個體, 可能還應該使用靜態類, 這樣可以免去執行個體化類的工作. 另, 在靜態方法中時不能使用$this 變數的, 因為靜態方法不屬於某個特定的執行個體.

PHP中使用範圍限定操作符時, 用變數作為類的名稱時不允許的.

  • parent:: 可用於調用父類中定義的成員方法。
  • parent::的追溯不僅於直接父類。
註:
在類裡面的時候,$this->func()和self::func()沒什麼區別。
在外部的時候,->必須是執行個體化後的對象使用; 而::可以是未執行個體化的類名直接調用。
舉個例子:
class Mytest{
function ccc($str){
echo $str;
}
}
Mytest::ccc("123456");
$object = new Mytest();
$object->ccc("123456"

php是個很詭異的語言。當然,這是對學習過C++或者Java等物件導向語言的人來說。
php可以定義靜態方法,然後通過className::staticMethod()形式來調用。非靜態方法,當然通過classObject->nonStaticMethod()使用。這個其他語言中也是如此,沒什麼大驚小怪的。可是,您能用className::nonStaticMethod()調用非靜態方法嗎?這方面恐怕Java和C++要冷汗直流了。其實,php自己也是滿臉黑線。為什麼這麼說呢?
先來看看物件導向的靜態和非靜態。物件導向的語言中,都會支援靜態方法。靜態方法,屬於類的固定資產的;非靜態方法,屬於類的執行個體的私人財產。在記憶體中,靜態方法,對於整個類也就只存了這麼一份;無論你new了多少個執行個體對象,它們共用的也就這麼一份。對於非靜態就不一樣了,你new幾個,記憶體就給你new幾份。另外,靜態方法內不可以調用非靜態方法,非靜態方法內卻可以調用靜態方法。這個就是靜態和非靜態區別。
物件導向用static關鍵字來定義靜態。未被標明是靜態方法,是不可以用類名加兩個冒號的形式調用的。php和其它很有區別的一點就是這個了:php中未被標明是靜態方法,也可以用類名加兩個冒號的形式調用。那麼為什麼php有這種文法?又為什麼感到很無奈呢?
-----以下說明php無奈的故事據相關資料改編,已經過演義處理--------
php之所以發展如此迅速,得益於它的速度。作為指令碼語言,php追求高速度和簡潔方便,所以選擇瞭解釋執行和使用過程方法。後來為了與國際接軌,引入了物件導向的概念。而就是在引入這個物件導向的特徵時,發生了一件令php目瞪口呆,最終無可奈何的事情。物件導向有個很重要的概念就是繼承。在繼承中,子類如果覆蓋父類的方法,同時需要調用父類的同名方法,該怎麼辦呢?php4版本提供了這樣一種方法:parentClassName::method()。提出此種方法之時,有識之士已經發現了問題:這個調用方式,不正是靜態方法的調用方式嗎?php4隨即答曰:不礙事。類中使用時,可以判斷此方式為子類正在調用父類方法;非類中使用時,就判斷為靜態調用了。所需要的只是發現此種調用時查詢一下方法映射就好了。其實,一想,也確實是那麼回事。php4後來想想,如果每次調用都檢驗一下此次調用是否合法,那多少也會影響效能,不如這個問題就交給程式員去控制吧:他們會知道只在類中使用此形式的調用的。唉,可惜天不遂人願。php4低估了程式員們的創造力!程式員們很快發現了這個方式,並且不餘遺力地使用起來。許多整合的API也開始使用這種怪癖的方式。php無奈了,隨即在php5中引入了另一種方式,使用關鍵字parent來調 用父類函數:parent::method()。但是,想要放棄php的非靜態方法的靜態調用,著實是不再可能了。
--------------------------------------------------------
不過,話說回來,這種php的怪癖方式,有什麼好處嗎?效能和記憶體佔用方面如何呢?
於是我開始推理了:定義了一個非靜態方法,靜態調用時,php首先轉換此方法為靜態定義,載入入靜態記憶體地區,然後執行。通常一次業務,只使用一個業務處理類中的一個方法,如果使用非靜態定義,靜態調用,記憶體中豈不是只載入了這個業務類中的一個方法,不是就實現了靜態方法的按需載入嗎?豈不是要省下一部分記憶體?效能方面,無論是靜態調用,還是對象調用,反正都是執行一個方法,效能還不是一樣?並且靜態調用非靜態定義方法還省了一個new語句。嗯,嗯。這麼想的同時,手就開始寫上了。
那麼實際如何呢?我做了一個小測試。


PHP code
t::start();t::end(); //消除t類首次載入的影響
t::start();
model_profile_base::getBaseInfo($uid);
t::end();


t::start();
$model = new model_profile_base();
$model->getBaseInfo($uid);
t::end();


 


t::start();
$model = new model_profile_base();
$model->getBaseInfo($uid);
t::end();


model_profile_base是處理基本資料的一個業務類,比較複雜,比較接近於項目中的業務處理實際。
下面是用到的計時和統計記憶體的t類的定義:

PHP code
<?php
function microtime_float()
{
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
class t{
static $start_time;
static $end_time;
static $start_memory;
static $end_memory;

public static function start()
{
self::$start_memory = memory_get_usage();
self::$start_time = microtime_float();
echo ‘<br/>Start @‘.self::$start_time.‘(‘.self::$start_memory.‘)|------->‘;
}

public static function end()
{
self::$end_time = microtime_float();
self::$end_memory = memory_get_usage();
echo ‘End @‘.self::$end_time.‘(‘.self::$end_memory.‘) :‘;
echo ‘|======= 共耗時:‘.(self::$end_time-self::$start_time).‘,共用記憶體:‘.(self::$end_memory-self::$start_memory);
}
}

第二行是靜態調用非靜態方法,第三行是正常調用非靜態方法。然後,我發現我的推理悲劇了。刷了好幾次頁面,統計結果在數量級上都差不多。靜態調用非靜態方法無論記憶體佔用還是效能上都不敢恭維。這樣的結果有點令人咂舌。
那麼,再試一下迴圈執行多次的結果:

PHP code
t::start();t::end(); //消除t類首次載入的影響
t::start();
for($i=0; $i<1000;++$i) model_profile_base::getBaseInfo($uid);
t::end();

t::start();
$model = new model_profile_base();
for($i=0; $i<1000;++$i) $model->getBaseInfo($uid);
t::end();


於是更讓人無語的結果出來了:

PHP code
Start @1287562243.5799(1009372)|------->End @1287562243.5799(1009372) :|======= 共耗時:3.0040740966797E-5,共用記憶體:0
Start @1287562243.58(1009372)|------->End @1287562244.1532(1587544) :|======= 共耗時:0.57321000099182,共用記憶體:578172
Start @1287562244.1532(1587544)|------->End @1287562244.6921(1587744) :|======= 共耗時:0.53887605667114,共用記憶體:200


除了兩種方式時間上開始接近外(並且還是正常調用比較利索),記憶體上仍然有天壤之別。失望之餘,查了下網上,發現也有人做了類似的測試。我就直接把結果拷上來吧:
(可能光看結果,會感覺有點難於理解,可以在這裡找到詳細說明:http://vega.rd.no/articles/php-static-method-performance)

測試結果 (ORDER BY time DESC):

PHP code
============Which method========================Time======
Inline calculation 0.0805 s
Normal function call 0.3438 s
Normal method called through object 0.4118 s
Static method called statically 0.4280 s
Unspecified method called through object() 0.4294 s
Unspecified method called statically() 0.6960 s


如此看來,靜態調用非靜態方法在效能和記憶體上都不佔優勢;另外,此種調用方法容易產生維護混亂。那麼,來個短而有力的總結:靜態調用非靜態方法不可取。
http://www.dabaoku.com/jiaocheng/biancheng/php/201102248955.shtml



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.