這一篇是完結篇,要談最後一部分:調用 功能的設計。
先看源碼:

    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,所以必須使用 開始($註記) 函數來使這項功能能夠使用,這是因為必須在整個調用功能的最外層設置一個時間點,讓報表中的比例欄位有一個可以比較的對象。

而報表中的比例欄位,指的是該函數佔整個執行時間的比例,同樣在出口一欄中也有比例欄位,但在出口中的比例欄位比較的對象則是該函數的總執行時間。
從比例欄位中,我們可以得知執行的瓶頸在哪裡。

而 從 - 至 欄位,則是我借用作業研究這門學科中的從至圖的概念,把調用該函數(從),以及該函數所調用的函數或是返回的函數(至),作一個調用次數上的分析,可以從這個欄位中看出函數間相互調用的關係。

進入 和 離開 函數中,是使用堆疊作為調用功能在計算相關數據的依據,所以在使用上會假設要量測的相關函數內的進入點及離開點都有作「正確」的設置。在這方面,我在 離開 函數上做的測試比較多,可以有效防止離開點未設置的錯誤,但不能防止在使用上被「錯誤」的設置。

不過我想這是使用者的責任,防呆措施我認為做到這個程度應該是可以接受的。
調用功能是這三大功能中最複雜的,主要是牽涉到一些資料結構運用上的問題。
arrow
arrow
    全站熱搜

    HACGIS 發表在 痞客邦 留言(0) 人氣()