php做用域限定符

雙冒號::被認爲是做用域限定操做符,用來指定類中不一樣的做用域級別。::左邊表示的是做用域,右邊表示的是訪問的成員。php

系統定義了兩個做用域,self和parent。self表示當前類的做用域,在類以外的代碼是不能使用這個操做符的。html

Program List:使用self做用域訪問父類中的函數

  
<?php
class NowaClass
{
function nowaMethod()
{
print '我在類 NowaClass 中聲明瞭。';
}
}

class ExtendNowaClass extends NowaClass
{
function extendNowaMethod()
{
print 'extendNowaMethod 這個方法在 ExtendNowaClass 這個類中聲明瞭。';
self::nowaMethod();
}
}

ExtendNowaClass::extendNowaMethod();

?>

程序運行結果:程序員

extendNowaMethod 這個方法在 ExtendNowaClass 這個類中聲明瞭。
我在類 NowaClass 中聲明瞭。

parent這個做用域很簡單,就是派生類用來調用基類的成員時候使用。app

Program List:使用parent做用域

    
<?php
class NowaClass
{
function nowaMethod()
{
print '我是基類的函數。';
}
}

class ExtendNowaClass extends NowaClass
{
function extendNowaMethod()
{
print '我是派生類的函數。';
parent::nowaMethod();
}
}

$obj = new ExtendNowaClass();
$obj -> extendNowaMethod();

?>

程序運行結果:函數

我是派生類的函數。
我是基類的函數。

Program List:用基類的方法訪問派生類的靜態成員

如何繼承一個存儲位置上的靜態屬性。性能

  
<?php
class Fruit 
{
public function get() 
{
        echo $this->connect();
    }
}
class Banana extends Fruit 
{
    private static $bananaColor;
    public function connect() 
{
        return self::$bananaColor = 'yellow';
    }
}
class Orange extends Fruit {
    private static $orange_color;
    public function connect() 
{
        return self::$orange_color = 'orange';
    }
}
$banana = new Banana();
$orange = new Orange();
$banana->get();
$orange->get();
?>

程序運行結果:學習

yellow
orange。

Program List:靜態函數初始化

在一個類中初始化靜態變量比較複雜,你能夠經過建立一個靜態函數建立一個靜態的構造器,而後在類聲明後立刻調用它來實現初始化。測試

    
<?php
class Fruit 
{
    private static $color = "White";
    private static $weigth;
    public static function init() 
{
        echo self::$weigth = self::$color . " Kilogram!";
    }
}
Fruit::init();
?>

程序運行結果:ui

White Kilogram!

Program List:一個簡單的單例模式例子

這個應該能夠幫到某些人吧。this

  
<?php
class Fruit
{
private static $instance = null;
    private function __construct()
    {
      $this-> color = 'Green';
    }
    public static function getInstance()
    {
      if(self::$instance == null)
      {
        print "Fruit object created!<br />";
        self::$instance = new self;
      }
      return self::$instance;
    }
    public function showColor()
    {
      print "My color is {$this-> color}!<br>";
    }
    public function setColor($color)
    {
      $this-> color = $color;
    }
}
  $apple = Fruit::getInstance(); // Fruit object created!
  $apple-> showColor(); // My color is Green!
  $apple-> setColor("Red");
  $apple-> showColor(); // My color is Red!
  $banana = Fruit::getInstance();
  $banana-> showColor(); // My color is Red!
  $banana-> setColor("Yellow");
  
  $apple-> showColor(); // My color is Yellow!
?>

程序運行結果:

Fruit object created!
My color is Green!
My color is Red!
My color is Red!
My color is Yellow!

轉載請註明:老高的自留地 » PHP做用域限定符::的幾個程序例子

 

 

在訪問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

 

 


 

 

 

有一個原則 若是某個方法中不包含$this變量 那麼這個方法就應該是靜態方法。若是不須要類的實例,可能還須要使用靜態類。在靜態方法中不能使用$this變量。

相關文章
相關標籤/搜索