php中static 靜態關鍵字

一直依賴對於php中static關鍵字比較模糊,只是在單例模式中用過幾回。上網查了查,沒有找到很全的介紹,本身總結一下。php

根據使用位置分爲兩部分 一、函數體中的靜態變量 二、類中的靜態屬性和方法html

1 函數體中的靜態變量java

static $a = 1;
function num1(){
    static $a = 0;
    return $a++;
}

function num2(){
    $a = 5555;
    global $a;
    echo $a++;
}

function num3(){
    static $a = 100;
    return $a++;
}

echo num1();    //0

num2();       //1
echo $a;       //2 

echo num3();    //100
echo num3();    //101
echo num3();    //102

 

從中咱們看出幾點c++

1 函數體中的靜態變量與全局中的靜態變量不衝突,只有在關鍵字global做用下才會使局部與全局統一編程

2 函數體中的靜態變量在函數調用的時候只會被初始化一次c#

由於靜態變量在全局數據區分配內存;此處要提一下 緩存在邏輯上大體區分爲 棧 堆 全局區  程序代碼區 文字常量區緩存

棧 存放變量名(會有一部分的整型,浮點型,字符串存放在此處)安全

堆 存放變量值函數

全局區 存放靜態變量,全局變量post

程序代碼區 存放要執行的函數及方法

文字常量區 存放常量等

大體是上面的樣子,至關至關不嚴格,可是能夠很好的幫助咱們記憶數據間的關係。

 

2 類中的靜態成員

類中的靜態成員包含靜態屬性和靜態方法

 class first{    public $num = 1;

//聲明一個靜態屬性 static $name = '456'; //聲明一個靜態方法 public static function self_use(){      echo self::$name;
echo self::out(); } public static function static_use(){ echo static::out(); } public static function method(){ echo 'first'; } //這是一個錯誤的調用 public function my_wrong(){ //echo self::dis(); } public function dis(){ echo '只是作一個展現'; } } class second extends first { public static function method(){ echo 'second'; } } $one = new first(); $one::$name; $one->self_use();
$one->static_use();


$two = new second();
$two->self_use();
$two->static_use();

關於類中的靜態方法咱們從兩個角度介紹 1 使用角度 2 理論角度

1 在實際使用中咱們須要注意幾點

a. 靜態方法能夠調用靜態屬性,禁止調用非靜態屬性。

b. 靜態方法內不容許出現$this,出現就停掉腳本。

c. 在靜態方法中調用類中其餘靜態方法有兩種格式 self:: 和 static 。根據輸出結果咱們瞭解到兩種方式的區別是 使用 self::method() 調用本方法所在類的 method() 方法。使用static::method(),會調用整個繼承家族最後定義的方法。

這個感受很繞繞啊,形象點理解就是在父類中聲明一個靜態方法A,子類中重寫了這個靜態方法A。在父類其餘方法中使用self調用A,會執行父類中A的方法;可是使用static調用,就會執行子類A的方法;

2 從理論角度介紹

早期的結構化編程幾乎都是靜態方法,出現面向對象以後,纔有了實例化方法的感念。而面向對象並不能徹底解決掉靜態方法使用的問題。咱們能夠這樣理解,靜態方法和實例化方法雖然都是類的,可是兩者的調用方式是不一樣的,靜態方法和屬性在類在使用class::就會被存進內存,而後使用。可是實例化方法和非靜態屬性,須要實例化 new以後纔會被存進內存使用。這就解釋了a 中靜態方法不能調用非靜態屬性,你靜態方法喊一嗓子就出來了,我非靜態屬性不行啊,沒批准(new)我出不來啊;而b中的$this是面向對象出來以後的產物專門用於實例化對象時候調用對象中的屬性和方法用的,是對象的專屬技能,這個技能靜態方法不能使用。

總結此處爲看了以後總結的,我木有那麼高水平:

你們對這個問題都有一個共識:那就是實例化方法更多被使用和穩妥,靜態方法少使用。有時候咱們對靜態方法和實例化方法會有一些誤解。

一、你們都覺得「 靜態方法常駐內存,實例方法不是,因此靜態方法效率高但佔內存。

事實上,他們都是同樣的,在加載時機和佔用內存上,靜態方法和實例方法是同樣的,在類型第一次被使用時加載。調用的速度基本上沒有差異。

 

二、你們都覺得「 靜態方法在堆上分配內存,實例方法在堆棧上

事實上全部的方法都不可能在堆或者堆棧上分配內存,方法做爲代碼是被加載到特殊的代碼內存區域,這個內存區域是不可寫的。

方法佔不佔用更多內存,和它是否是static沒什麼關係。   
  由於字段是用來存儲每一個實例對象的信息的,因此字段會佔有內存,而且由於每一個實例對象的狀態都不一致(至少不能認爲它們是一致的),因此每一個實例對象的全部字段都會在內存中有一分拷貝,也由於這樣你才能用它們來區分你如今操做的是哪一個對象。   
  但方法不同,不論有多少個實例對象,它的方法的代碼都是同樣的,因此只要有一份代碼就夠了。所以不管是static仍是non-static的方法,都只存在一份代碼,也就是隻佔用一分內存空間。   
  一樣的代碼,爲何運行起來表現卻不同?這就依賴於方法所用的數據了。主要有兩種數據來源,一種就是經過方法的參數傳進來,另外一種就是使用class的成員變量的值……

 

三、你們都覺得「實例方法須要先建立實例才能夠調用,比較麻煩,靜態方法不用,比較簡單

事實上若是一個方法與他所在類的實例對象無關,那麼它就應該是靜態的,而不該該把它寫成實例方法。因此全部的實例方法都與實例有關,既然與實例有關,那麼建立實例就是必然的步驟,沒有麻煩簡單一說。

固然你徹底能夠把全部的實例方法都寫成靜態的,將實例做爲參數傳入便可,通常狀況下可能不會出什麼問題。

從面向對象的角度上來講,在抉擇使用實例化方法或靜態方法時,應該根據是否該方法和實例化對象具備邏輯上的相關性,若是是就應該使用實例化對象  反之使用靜態方法。這只是從面向對象角度上來講的。

若是從線程安全、性能、兼容性上來看  也是選用實例化方法爲宜。

 

咱們爲何要把方法區分爲:靜態方法和實例化方法 ?

若是咱們繼續深刻研究的話,就要脫離技術談理論了。早期的結構化編程,幾乎全部的方法都是「靜態方法」,引入實例化方法概念是面向對象概念出現之後的事情了,區分靜態方法和實例化方法不能單單從性能上去理解,建立c++,java,c#這樣面嚮對象語言的大師引入實例化方法必定不是要解決什麼性能、內存的問題,而是爲了讓開發更加模式化、面向對象化。這樣說的話,靜態方法和實例化方式的區分是爲了解決模式的問題。

拿別人一個例子說事:

 好比說「人」這個類,每一個人都有姓名、年齡、性別、身高等,這些屬性就應該是非靜態的,由於每一個人都的這些屬性都不相同;但人在生物學上屬於哪一個門哪一個綱哪一個目等,這個屬性是屬於整我的類,因此就應該是靜態的——它不依賴與某個特定的人,不會有某我的是「脊椎動物門哺乳動物綱靈長目」而某我的倒是「偶蹄目」的。

 

 參考文獻:

PHP中靜態方法和實例化方法的區別

static關鍵字及變量存儲位置總結

相關文章
相關標籤/搜索