close
這一篇是完結篇,要談最後一部分:調用 功能的設計。
先看源碼:
function 開始($註記 = false){
$this->調用 = array();
$this->堆疊 = array();
$this->從 = array();
$this->至 = array();
if (false == $註記){
$註記 = md5(uniqid(rand(), true));
}
$this->量測 = true;
$this->註記 = $註記;
$this->進入($註記);
}
function 結束(){
if (false == $this->量測) {
return;
}
$堆疊 = &$this->堆疊;
if (1 < count($堆疊)) {
$堆疊 = array(reset($堆疊));
}
$this->離開($this->註記);
$this->量測 = false;
}
function 進入($註記){
if (false == $this->量測){
return;
}
$預設 = 0;
$索引 = count($this->堆疊);
if (0 < $索引){
$調用 = $this->堆疊[$索引 - 1][0];
$從 = &$this->從[$註記][$調用];
$至 = &$this->至[$調用][$註記];
變數:預設($從, $預設);
變數:預設($至, $預設);
$從++;
$至++;
}
$次數 = &$this->調用[$註記]['次數'];
變數:預設($this->調用[$註記]['註記'], $註記);
變數:預設($次數, $預設);
$次數++;
$this->堆疊[] = array($註記, microtime(true));
}
function &離開($註記, $出口 = 0, &$輸出 = ''){
$離開 = microtime(true);
$索引 = count($this->堆疊);
if (false == $this->量測 || 0 == $索引 || $this->堆疊[$索引 - 1][0] != $註記){
return $輸出;
}
$預設 = 0;
list($註記, $進入) = array_pop($this->堆疊);
$耗時 = abs($進入 - $離開);
$累計 = &$this->調用[$註記]['累計'];
$出口次數 = &$this->調用[$註記]['出口'][$出口]['次數'];
$出口累計 = &$this->調用[$註記]['出口'][$出口]['累計'];
變數:預設($this->調用[$註記]['出口'][$出口]['出口'], $出口);
變數:預設($累計, $預設);
變數:預設($出口次數, $預設);
變數:預設($出口累計, $預設);
$累計 += $耗時;
$出口次數++;
$出口累計 += $耗時;
return $輸出;
}
private function &整理:調用($註記){
$預設 = array();
$輸出 = array();
$調用 = &$this->調用[$註記];
if (false == isset($調用)){
return $輸出;
}
$this->整理:出口($註記);
$輸出 = $調用;
$輸出['從'] = 變數:預設($this->從[$註記], $預設);
$輸出['至'] = 變數:預設($this->至[$註記], $預設);
$比較 = &$this->調用[$this->註記]['累計'];
$預設 = 0;
變數:預設($比較, $預設);
$輸出['比例'] = 100 * 數學:除法($調用['累計'], $比較);
$輸出['比例'] = number_format($輸出['比例'], 2, '.', '') . ' %';
return $輸出;
}
private function 整理:出口($註記){
$調用 = &$this->調用[$註記];
if (false == isset($調用)){
return;
}
foreach ($調用['出口'] as &$出口){
$出口['比例'] = 100 * 數學:除法($出口['累計'], $調用['累計']);
$出口['比例'] = number_format($出口['比例'], 2, '.', '') . ' %';
}
}
function &彙整:調用($表格 = false){
if ($this->量測) {
$this->結束();
}
$輸出 = array();
foreach ($this->調用 as $註記 => &$調用){
$輸出[$註記] = &$this->整理:調用($註記);
if (0 == count($輸出[$註記])) {
unset($輸出[$註記]);
}
}
if ($表格) {
$輸出 = 網頁:表格($輸出, $this->編碼['調用'], '調用', $this->屬性);
}
return $輸出;
}
由於輸出的報表比較複雜,所以彙整的部份我拆成三塊來作,運用的技巧跟測試系列相關的作法一樣,都是一層層套疊:彙整:調用=>整理:調用=>整理:出口。
這樣的設計是因為比較容易看懂每個區塊的意圖,如果全部寫在同一個函數中,源碼的長度變得比較長,相互之間要使用的變數名稱可能要重新命名,也不容易看懂,所以我會把這樣的函數拆出來。
由於是類別內的成員,可以將一部分的函數設成private,使外部無法存取,也由於在類別內,可使用的假設限制也比較寬,不用擔心傳進來的參數會有格式不符的問題。
$量測 是這整個功能的一個旗標,預設是false,所以必須使用 開始($註記) 函數來使這項功能能夠使用,這是因為必須在整個調用功能的最外層設置一個時間點,讓報表中的比例欄位有一個可以比較的對象。
而報表中的比例欄位,指的是該函數佔整個執行時間的比例,同樣在出口一欄中也有比例欄位,但在出口中的比例欄位比較的對象則是該函數的總執行時間。
從比例欄位中,我們可以得知執行的瓶頸在哪裡。
而 從 - 至 欄位,則是我借用作業研究這門學科中的從至圖的概念,把調用該函數(從),以及該函數所調用的函數或是返回的函數(至),作一個調用次數上的分析,可以從這個欄位中看出函數間相互調用的關係。
進入 和 離開 函數中,是使用堆疊作為調用功能在計算相關數據的依據,所以在使用上會假設要量測的相關函數內的進入點及離開點都有作「正確」的設置。在這方面,我在 離開 函數上做的測試比較多,可以有效防止離開點未設置的錯誤,但不能防止在使用上被「錯誤」的設置。
不過我想這是使用者的責任,防呆措施我認為做到這個程度應該是可以接受的。
調用功能是這三大功能中最複雜的,主要是牽涉到一些資料結構運用上的問題。
先看源碼:
function 開始($註記 = false){
$this->調用 = array();
$this->堆疊 = array();
$this->從 = array();
$this->至 = array();
if (false == $註記){
$註記 = md5(uniqid(rand(), true));
}
$this->量測 = true;
$this->註記 = $註記;
$this->進入($註記);
}
function 結束(){
if (false == $this->量測) {
return;
}
$堆疊 = &$this->堆疊;
if (1 < count($堆疊)) {
$堆疊 = array(reset($堆疊));
}
$this->離開($this->註記);
$this->量測 = false;
}
function 進入($註記){
if (false == $this->量測){
return;
}
$預設 = 0;
$索引 = count($this->堆疊);
if (0 < $索引){
$調用 = $this->堆疊[$索引 - 1][0];
$從 = &$this->從[$註記][$調用];
$至 = &$this->至[$調用][$註記];
變數:預設($從, $預設);
變數:預設($至, $預設);
$從++;
$至++;
}
$次數 = &$this->調用[$註記]['次數'];
變數:預設($this->調用[$註記]['註記'], $註記);
變數:預設($次數, $預設);
$次數++;
$this->堆疊[] = array($註記, microtime(true));
}
function &離開($註記, $出口 = 0, &$輸出 = ''){
$離開 = microtime(true);
$索引 = count($this->堆疊);
if (false == $this->量測 || 0 == $索引 || $this->堆疊[$索引 - 1][0] != $註記){
return $輸出;
}
$預設 = 0;
list($註記, $進入) = array_pop($this->堆疊);
$耗時 = abs($進入 - $離開);
$累計 = &$this->調用[$註記]['累計'];
$出口次數 = &$this->調用[$註記]['出口'][$出口]['次數'];
$出口累計 = &$this->調用[$註記]['出口'][$出口]['累計'];
變數:預設($this->調用[$註記]['出口'][$出口]['出口'], $出口);
變數:預設($累計, $預設);
變數:預設($出口次數, $預設);
變數:預設($出口累計, $預設);
$累計 += $耗時;
$出口次數++;
$出口累計 += $耗時;
return $輸出;
}
private function &整理:調用($註記){
$預設 = array();
$輸出 = array();
$調用 = &$this->調用[$註記];
if (false == isset($調用)){
return $輸出;
}
$this->整理:出口($註記);
$輸出 = $調用;
$輸出['從'] = 變數:預設($this->從[$註記], $預設);
$輸出['至'] = 變數:預設($this->至[$註記], $預設);
$比較 = &$this->調用[$this->註記]['累計'];
$預設 = 0;
變數:預設($比較, $預設);
$輸出['比例'] = 100 * 數學:除法($調用['累計'], $比較);
$輸出['比例'] = number_format($輸出['比例'], 2, '.', '') . ' %';
return $輸出;
}
private function 整理:出口($註記){
$調用 = &$this->調用[$註記];
if (false == isset($調用)){
return;
}
foreach ($調用['出口'] as &$出口){
$出口['比例'] = 100 * 數學:除法($出口['累計'], $調用['累計']);
$出口['比例'] = number_format($出口['比例'], 2, '.', '') . ' %';
}
}
function &彙整:調用($表格 = false){
if ($this->量測) {
$this->結束();
}
$輸出 = array();
foreach ($this->調用 as $註記 => &$調用){
$輸出[$註記] = &$this->整理:調用($註記);
if (0 == count($輸出[$註記])) {
unset($輸出[$註記]);
}
}
if ($表格) {
$輸出 = 網頁:表格($輸出, $this->編碼['調用'], '調用', $this->屬性);
}
return $輸出;
}
由於輸出的報表比較複雜,所以彙整的部份我拆成三塊來作,運用的技巧跟測試系列相關的作法一樣,都是一層層套疊:彙整:調用=>整理:調用=>整理:出口。
這樣的設計是因為比較容易看懂每個區塊的意圖,如果全部寫在同一個函數中,源碼的長度變得比較長,相互之間要使用的變數名稱可能要重新命名,也不容易看懂,所以我會把這樣的函數拆出來。
由於是類別內的成員,可以將一部分的函數設成private,使外部無法存取,也由於在類別內,可使用的假設限制也比較寬,不用擔心傳進來的參數會有格式不符的問題。
$量測 是這整個功能的一個旗標,預設是false,所以必須使用 開始($註記) 函數來使這項功能能夠使用,這是因為必須在整個調用功能的最外層設置一個時間點,讓報表中的比例欄位有一個可以比較的對象。
而報表中的比例欄位,指的是該函數佔整個執行時間的比例,同樣在出口一欄中也有比例欄位,但在出口中的比例欄位比較的對象則是該函數的總執行時間。
從比例欄位中,我們可以得知執行的瓶頸在哪裡。
而 從 - 至 欄位,則是我借用作業研究這門學科中的從至圖的概念,把調用該函數(從),以及該函數所調用的函數或是返回的函數(至),作一個調用次數上的分析,可以從這個欄位中看出函數間相互調用的關係。
進入 和 離開 函數中,是使用堆疊作為調用功能在計算相關數據的依據,所以在使用上會假設要量測的相關函數內的進入點及離開點都有作「正確」的設置。在這方面,我在 離開 函數上做的測試比較多,可以有效防止離開點未設置的錯誤,但不能防止在使用上被「錯誤」的設置。
不過我想這是使用者的責任,防呆措施我認為做到這個程度應該是可以接受的。
調用功能是這三大功能中最複雜的,主要是牽涉到一些資料結構運用上的問題。
全站熱搜
留言列表