PHP物件的引用及物件優化策略

pythontab發表於2014-04-16

當PHP5的出現物件導向思想,我們在構造PHP程式時候就有了對程式的新的總結,把物件特性封裝到類,特別是當PHP框架應用到實際專案中,構造類的物件和呼叫類物件出現了很大的講究。

我們很多時候會發現,我們在寫一些程式的時候,期望只要第一次構造了該物件,以後操作就是直接對該物件進行其他動作的操作,其實,每個類在構造一個物件後都是可以實現物件對方法或屬性的呼叫,這是物件導向最為基本的做法。但是如果你研究了一些框架集合後,特別是應用到MVC模式下的框架開發程式,你會發現一個Controller裡面會有很多個action,也就是我們所說的控制器裡的方法有很多,當然你也會發現當一個控制器控制一個事務物件操作的時候,裡面會出現很多次構造物件,運算元據集合的動作,但是你也會發現如果每次都是靠NEW方式去構造物件的話,無疑就是一次次給自己的記憶體空間增加負擔。因為構造一個新的物件無疑就是要分配一個新的記憶體空間給它,但是如果你其實只是要求同一個物件動作的延續,那麼試圖尋找已經構造好的物件,並呼叫它無疑是個很不錯的想法。所謂,同一物件的動作的延續,這個問題其實也很好解釋,比如我現在構造一個控制器類為Controller A,裡面是對資料Model A的一個新增,刪除等操作,那麼我們的控制動作就會存在假設為action Add ,actionDelete ,按照常規,我們通常利用框架集的單點入口原理,通過路由分配器程式找到了Controller A,但是裡面會如果要單獨呼叫actionAdd或,actionDelete ,且兩個動作都是對Model A進行的資料操作,每次操作按照常規都必須構造資料物件,然後呼叫SQL去執行資料庫操作,假設構造兩個動作都要去操作同一個資料物件時候呼叫的方法時候都是在使用同一個語句$a=new A()這種形式的話,兩次操作其實就產生了兩個物件,也就同時佔用兩倍的記憶體空間,試想不過就是要求同一個人去實施兩個動作,有必要兩個人分別去做兩件事情麼,顯然這種條件下是等於資源浪費,而且當動作多了的時候就會出現大量物件資源佔用記憶體嚴重導致系統效能下降,最終嚴重的就導致崩潰。

其實,我們在寫很多程式的時候也都一再強調,技術完成功能只是最基礎的一部分,一個好的程式或是網站,要研究的不僅僅是功能問題,更重要的是整體效能,特別是對於大型講究效用的程式來說效能是非常重要的。這點上框架集合是非常不錯的典範,它們善於合理使用地址引用。讓如果能一個物件處理的事情,就讓一個物件來處理,把足夠的空間留給其他不同的類別的物件。

框架集合解決物件資源是否重用的最好的方法就是全域性變數的使用,當你的物件建立存在的時候,一般是第一次建立時候,就把它裝載到全域性變數中,我們也可以叫做註冊物件,所以以後考慮物件呼叫方法的時候就直接去Check全域性變數中是該類物件,也就是說看其是否註冊了該物件,如果存在就直接返回該類物件,並告知地址,以便引用。這樣以來是很容易實現物件地址引用的。當建立所有物件變數指向同一記憶體空間的時候,我們說此刻他們只是名字不同,實際是同一物件。

於是,我們可以建立了這樣的程式程式碼如下:

<?php
$GLOBALS['objects']['classname']=null; //是否註冊類,類名變數
$GLOBALS['objects']['obj']=null; //物件變數
function & getSingle($classname){
if($GLOBALS['objects']['classname']==$classname){
return $GLOBALS['objects']['obj'];
}else
{
$object= new $classname();
$GLOBALS['objects']['classname']=$classname;
$GLOBALS['objects']['obj']=&$object;
return $GLOBALS['objects']['obj'];
}
}
class Test{
var $p1;
function Test(){
$this->p1=1;
}
function add()
{
$this->p1++;
}
function show()
{
return $this->p1;
}
}
$test1=&getSingle('Test');
$test1->add();
$test2=&getSingle('Test');
echo $test2->show();
$test2->add();
$test3=&getSingle('Test');
echo $test3->show();
if($test1===$test2)
echo 'yes';
else
echo 'no';
?>

根據第一次建立物件後,第二次呼叫讀取資料時候的必然是以原物件為基礎的再操作,可以由後面的程式看到$test2去資料時候結果是2,然後進行add操作後,由$test3再讀取時候發現結果為3顯然是因為動作2完成的效果。由此,我們看到了利用同一物件進行分步操作的好處所在,在這裡是因為我們將程式碼放在了一起,當然我們在使用框架的使用經常會出現這樣的情況就是將上面的$test1,$test2,$test3以及他們的動作分別放在同一個控制器的不同動作action中,因為動作塊是相互獨立的,因此,三個物件變數誰先誰後觸發最早建立這個物件記憶體空間都是隨機而定的。第一次先是檢測全域性變數中是否註冊了該物件,並檢查物件地址是否儲存在全域性變數中,以後就是對該物件地址進行比對和存取。


相關文章