require_once的效能其實很低下_PHP教程

來源:互聯網
上載者:User
經過測試,require_once是一個效能低下的文法結構,當然,這個效能低下是相對於require而言的,本文闡述我們項目目前使用的require方式,通過實驗代碼證明其高效性,同時,描述我們在使用過程中遇到的問題,避免他人在同一個石頭上絆倒。

  • require: 引入一個檔案,運行時編譯引入.
  • require_once: 功能等同於require,只是當這個檔案被引用過後,不再編譯引入。

上面就是兩者的區別。可以看出,兩者的不同僅在於require_once有一個判斷是否已經引用過的機制。通過網路搜尋,可以看到很多關於require_once效能比require低很多的資料,這裡就不再做這個實驗。

我們項目中的做法是: 在每個檔案起始位置定義一個全域變數,require的時候,使用isset($xxxxxx) or require 'xxxxx.php';

這種做法有什麼不足呢?

全域變數以$xxx方式定義的時候,如果該檔案在函數內被require,該變數會被解析為函數的局部變數,而不是全域的,因此,函數內部的isset($xxx) or require 'xxx.php'這個文法結構會失效,帶來的結果當然是意料不到的,比如,類的重定義,方法的重定義等等。

前車之鑒,所以,全域變數的定義,請使用$GLOBALS['xxx'],require的時候,使用isset($GLOBALS['xxx']) or require 'xxx.php';,使用GLOBALS會比直接定義稍慢,但總比錯是要好很多的。

由於我們之前的全域變數是直接定義的,今天在和同事討論的過程中,想到另外一種寫法:

定義的位置仍然使用$xxx方式直接定義,require的方法中進行修改(檔案頭部定義的全域變數和檔案名稱是有關聯的)。

function ud_require($xxx) {global $$xxx;    isset($$xxx) or require $xxx . '.php';}

這種方式使用了動態變數,經過和直接的GLOBALS方式比較,有兩個顯著缺點:

  1. 效能,由於動態變數的引入,比GLOBALS方式慢2倍左右。
  2. 無法解決間接引用問題,因為我們無法預知被間接引用的檔案名稱,也就無法用global去聲明那些被間接引用的檔案中定義的標記性全域變數了。

好了,下面是我對GLOBALS方式的require和require_once的測試:

require_requireonce.php

/n";  $start = microtime(true);  while($j ++ < 1000000) test1('require_requireonce_require.php');  $end = microtime(true);  echo "使用方法的isset or require方式: " . ($end - $start) . "
/n"; $start = microtime(true); while($k ++ < 1000000) test2(); $end = microtime(true); echo "require_once方式: " . ($end - $start) . "
/n"; ?>

require_requireonce_require.php (用於測試require的被引入檔案)

  

require_requireonce_requireonce.php (用於測試require_once的被引入檔案)

  

下面是測試的結果(單位: 秒):

  • 不使用方法的isset or require方式: 0.22953701019287
  • 使用方法的isset or require方式: 0.23866105079651
  • require_once方式: 2.3119640350342

可以看出,不套一個方法的require速度是比使用方法的略快的,兩者速度都是require_once的10倍左右。

那麼,效能損耗究竟在哪裡呢?

上面require_requireone.php檔案中的test1方法中,我注釋了一句pathinfo($filename),因為,我本來意圖是使用檔案名稱不帶尾碼作為標記性的全域變數名的,但是,當我使用pathinfo之後,我發現這種方式的效能消耗和require_once基本一致了。因此,我在那裡單獨的加了一個pathinfo的調用,又做了測試,果然是pathinfo在搗鬼。所以,後面我就修改為了現在的版本,直接使用檔案名稱作為變數名,如果你害怕檔案名稱重複,那不妨加上路徑名...

猜測: 加上pathinfo之後,require和require_once的效能消耗基本一致,那我們是否可以猜測PHP內部對require_once的處理是基於它的呢?據說PHP5.3中對require_once做了顯著的最佳化,但是,我測試過程中使用的是PHP5.3.5版本,仍然能夠看到和require明顯的差距,難道只是比之前版本較大最佳化?這個倒還沒有測試....

嘗試把test1方法做了如下修改:isset($GLOBALS[substr($filename, 0, strlen($filename) - 4)]) or require $filename;

使用手動的字串截取,當然,截取是要耗時的,不過比pathinfo的版本是要好一點的。這次的測試結果是:

  • 不使用方法的isset or require方式: 0.21035599708557
  • 使用方法的isset or require方式: 0.92985796928406
  • require_once方式: 2.3799331188202

對於require_once修改為isset or require方式,需要注意以下幾方面:

  1. 每個檔案頭部定義唯一的一個標記性變數,使用$GLOBALS['XXX'] = 1;的方式定義,並且,建議變數名是檔案名稱或帶路徑的檔案名稱(如果單獨的檔案名稱會重複)
  2. 定義一個自訂require方法:
  3. function ud_require_once($filename) {isset($GLOBALS[$filename]) or require $filename;}

http://www.bkjia.com/PHPjc/752440.htmlwww.bkjia.comtruehttp://www.bkjia.com/PHPjc/752440.htmlTechArticle經過測試,require_once是一個效能低下的文法結構,當然,這個效能低下是相對於require而言的,本文闡述我們項目目前使用的require方式,通...

  • 相關文章

    聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.