PHP 優化詳解

筆者收集的這些技巧來源較廣,完整性不能保證。 因爲數量較多,這些優化技巧沒有通過測試。請各位看官在使用以前自行測試,畢竟這些技巧是否能派上用場,仍是須要由PHP所在的獨特環境所決定的。php

目錄索引mysql

  1. 找到瓶頸(Finding the Bottleneck)
  2. 緩存 (Caching)
  3. 編譯 vs. 解釋(Compiling vs. Interpreting)
  4. 代碼減肥 (Content Reduction)
  5. 多線程與多進程(Multithreading & Multiprocessing)
  6. 字符串(Strings)
  7. 正則表達式(Regular Expressions)
  8. 迭代結構 (Iteration Constructs (for, while))
  9. 選擇結構 (Selection Constructs (if, switch))
  10. 函數與參數 (Functions & Parameters)
  11. 面向對象結構 (Object-Oriented Constructs)
  12. Session處理 (Session Handling)
  13. 類型轉換 (Type Casting)
  14. 壓縮(Compression)
  15. 錯誤處理(Error Handling)
  16. 聲明、定義與範圍(Declarations, Definitions, & Scope)
  17. 內存泄漏(Memory Leaks)
  18. 不要重複發明輪子(Don’t Reinvent the Wheel)
  19. 代碼優化(Code Optimization)
  20. 使用RAM(Using RAM Instead of DASD)
  21. 使用服務(Using Services (e.g., SQL))
  22. 安裝與配置(Installation & Configuration)
  23. 其餘(Other)
 

找到瓶頸(Finding the Bottleneck)

面對一個性能問題是,第一步永遠是找到問題產生的緣由,而不是去看技巧列表。搞明白產生瓶頸的緣由,找到目標而且實施修復,而後再從新測試。查找瓶頸只是萬里長征的第一步,這裏有些經常使用技巧,但願對最重要的第一步找到瓶頸能有所幫助。git

  • 使用監控方法(好比監控寶),進行benchmark和監控,網絡,特別是網絡情況瞬息萬變,作得好的話5分鐘就能夠找到瓶頸。
  • 剖析代碼。必須瞭解那部分代碼耗時最多,在這些地方多多關注。
  • 想找到瓶頸,請檢查每一個資源請求(好比,網絡、CPU、內存、共享內存、文件系統、進程管理、網絡鏈接等等……)
  • 先對迭代結構和複雜的代碼進行benchmark
  • 在在真實負載下用真實數據進行真實測試,固然,若是能夠最好用產品服務器。

緩存 (Caching)

有些人認爲緩存是解決性能問題最有效的辦法之一,試試這些:正則表達式

  • 使用OPCODE(操做碼)緩存,這樣腳本就不會在每次訪問時從新編譯一次。好比:啓用Windows平臺上的windows緩存擴展。能夠緩存opcode,文件,相對路徑,session數據和用戶數據。
  • 考慮在多服務器環境下使用分佈式緩存
  • 在調用imap_header()以前先調用imap_headers()

編譯 vs. 解釋(Compiling vs. Interpreting)

將PHP源碼編譯成機器碼。動態解釋執行一樣的編譯,但它是按行執行的。編譯爲opcode是折中選擇,它能夠將PHP源碼翻譯爲opcode,以後opcode再轉爲機器碼。如下爲關於編譯與解釋的相關技巧:算法

  • 上線以前將PHP代碼編譯爲機器碼。opcode緩存儘管並非最好的選擇,但依舊比解釋型來得強。或者,考慮將PHP代碼編譯成一個C擴展。
  • PHP的opcode編譯器(bcompiler)還不能在產品環境中使用,可是開發者應該關注http://php.net/manual/en/book.bcompiler.php.

代碼減肥 (Content Reduction)

越少越塊。 這些技巧能夠幫助減小代碼:sql

  • 每頁提供更少的功能
  • 清理網頁內容
  • 若是解釋型執行,請清理註釋和其餘空白
  • 減小數據庫查詢

多線程與多進程(Multithreading & Multiprocessing)

由快到慢依次爲:數據庫

  1. 多線程(單一進程中)
  2. 多進程(好比,pcntl_fork,計劃任務)
  3. 單進程(一行又一行)

PHP不支持多線程,可是能夠用C寫多線程的PHP擴展。有一些辦法可使用多進程或模擬多進程,但支持的並非很好,沒準兒比單進程還慢。編程

字符串(Strings)

字符串處理,是大多數編程語言中最經常使用的操做之一。這裏有些技巧能夠幫咱們讓字符串處理速度更快一些:windows

  • PHP的鏈接運算(點運算),是最快的連接方式
  • 避免在print中連接字符串,用逗號分割後用ECHO
  • 儘量使用str_前綴的字符串函數替代正則表達式
  • pos()比preg_mach()和ereg()都快
  • 有人說單引號包裹字符串比雙引號更快,有人說沒有區別。固然,若是想在字符串中引用變量,單引號沒戲。
  • 若是想判斷字符串長度是否小於某值(好比5),請使用isset($s[4])<5。
  • 如需將多個小字符串鏈接成一個大字符串,試着先開啓ob_start輸出緩存,再用echo輸出到緩衝區,完成後使用ob_get_contents讀取字符串

正則表達式(Regular Expressions)

正則表達式爲們帶來了靈活多樣的比較與查找字符串的方法,單他的性能開銷卻着實不低數組

  • 儘量使用STR_前綴的字符串處理函數代替正則表達式
  • 使用[aeiou]的不是(a|e|i|o|u)
  • 正則表達式越簡單速度越快
  • 儘量不要設置PCRE_DOTALL修飾符
  • 用^.*代替.*
  • 簡化正則表達式。(好比使用a*代替(a+)*

迭代結構 (Iteration Constructs (for, while))

迭代(重複,循環)是最基本的結構化編程方法,很難想像有不使用它的程序。這裏有些技巧,幫助咱們改進迭代結構的性能:

  • 儘量講代碼移出到循環外(函數調用、SQL查詢等等……)
  • 使用i=maxval;while(i–)代替for(i=0;i<maxval;i++),這樣能夠減小一個操做,若是maxval是一個函數調用就更明顯了。
  • 使用foreach迭代集合與數組

選擇結構 (Selection Constructs (if, switch))

與迭代結構相同,選擇結構也是最基本的結構化變成方法。如下技巧或許能改善性能:

  • switches和else-if中,應該將最近常出現true的列在前面,較少出現true的請靠後
  • 有人說if-else比swtich/case快,固然,有人反對。
  • 用elseif替代else if.

函數與參數 (Functions & Parameters)

將函數的代碼分解成小函數代碼能夠消除冗餘,讓代碼具備可讀性,但代價是什麼?這裏有些技巧,以幫助更好的使用函數:

  • 引用傳遞出對象和數組,而不是傳值
  • 若是隻在一個地方使用,使用內聯。若是在多個地方調用,考慮內聯,但請注意可維護性
  • 瞭解你所用函數的複雜度。好比similar_text()爲O(N^3),這意味着字符串長度增長一倍,處理時間將增長8倍
  • 不要經過「返回引用」來提高性能,引擎會自動優化它。
  • 以常規方式調用函數,而不是使用call_user_func_array()或eval()

面向對象結構 (Object-Oriented Constructs)

PHP的面向對象特性,可能會影響到性能。如下提示能夠幫助咱們儘可能減小這種影響:

  • 不是一切都須要面向對象, 性能的損失可能會超過其優勢自己
  • 建立對象比較慢
  • 若是能夠,儘量時候用數組而不是對象
  • 若是一個方法能夠靜態化,請靜態聲明
  • 函數調用比派生類方法調用要快,派生類方法調用比基類調用要快
  • 考慮將基類中最經常使用的代碼複製到派生類中,但要注意維護性隱患
  • 避免使用原生的getters與setters。若是不須要他們,請刪除而且屬性公開
  • 建立複雜的PHP類時,考慮使用單件模式

Session處理 (Session Handling)

建立sessions有不少好處,但有時會產生不必的性能開支。如下技巧能夠幫助咱們最大限度減小性能開支:

  • 不要使用auto_start
  • 不要啓用use_trans_sid
  • 將session_cache_limited設置爲private_no_expire
  • 爲虛擬主機(vhost)中的每一個用戶分配本身的目錄
  • 使用基於內存的session處理,而不是基於文件的session處理

類型轉換 (Type Casting)

從一種類型轉換爲另外一種類型須要成本

壓縮(Compression)

在傳輸前,壓縮文本和數據:

  • 使用ob_start()在代碼起始處
  • 使用ob_gzhandler()能夠下載提速,可是注意CPU開支
  • Apache的mod_gzip模塊能夠即便壓縮

錯誤處理(Error Handling)

錯誤處理影響性能。咱們能作的是:

  • 記錄錯誤日誌,別再使用「@」抑制錯誤報告,抑制對性能同樣有影響
  • 不要只檢查錯誤日誌,警告日誌同樣須要處理

聲明、定義與範圍(Declarations, Definitions, & Scope)

建立一個變量、數組或者對象,對性能都有影響:

  • 有人說,聲明和使用全局變量/對象,比局部變量/對象要快,有人反對。請測試再決定。
  • 在使用變量前聲明全部變量,不要聲明不使用的變量
  • 在循環中儘量使用$a[],避免使用$a=array(…)

內存泄漏(Memory Leaks)

若是內存分配後不釋放,這絕對是個問題:

  • 堅持釋放資源,不要期望自帶/自動的垃圾回收
  • 使用完後儘可能註銷(unset)變量,尤爲是資源類和大數組類型的
  • 使用完畢就關閉數據庫鏈接
  • 每次使用ob_start(),記得ob_end_flush()或者ob_end_clean()

不要重複發明輪子(Don’t Reinvent the Wheel)

爲何要花費時間去解決別人已經解決的問題?

  • 瞭解PHP,瞭解它的功能和擴展。若是你不知道,可能會沒法利用一些現成的功能
  • 使用自帶的數組和字符串函數,它們絕對是性能最好的。
  • 前人發明的輪子,並不意味着在你的環境下吸能是最好的,多多測試

代碼優化(Code Optimization)

  • 使用一個opcode optimizer
  • 若是將被解釋運行,請精簡源碼

使用RAM(Using RAM Instead of DASD)

RAM比磁盤快不少不少,使用RAM能夠提高一些性能:

  • 移動文件到Ramdisk
  • 使用基於內存的session處理,而不是基於文件的session處理

使用服務(Using Services (e.g., SQL))

SQL常常被用來訪問關係型數據庫,但咱們的PHP代碼能夠訪問許多不一樣的服務。下面是一些訪問服務是須要牢記的:

  • 不要一遍又一遍地問服務器向東的事情。使用memoization緩存第一次的結果,之後訪問直奔緩存;
  • 在SQL中,使用mysql_fetch_assoc()代替mysql_fetch_array(),能夠減小結果集中的整數索引。以字段名訪問結果集,而不用索引數字。
  • 對於Oracle數據庫,若是沒有足夠的可用內存,增長oci8.default_prefetch。將oci8.statement_cache_size設置爲應用中的語句數
  • 請使用mysqli_fetch_array()替換mysqli_fetch_all(), 除非結果集將發送到其餘層進行處理。

安裝與配置(Installation & Configuration)

安裝與配置PHP時,請考慮性能:

  • 添加更多內存
  • 刪除競爭性的應用與服務
  • 只編譯所須要用的擴展
  • 將PHP靜態編譯進APACHE
  • 使用-O3 CFLAGS開啓全部編譯器優化
  • 只安裝所需使用的模塊
  • 升級到最新版本的次要版本。主板本升級,等到第一次bug修復後再進行,固然,也別等過久
  • 爲多CPU環境進行配置
  • 使用 -enable-inline-optimization
  • 設置session.save_handler=mm ,以 -with-mmto編譯,使用共享內存
  • 使用RAM disk
  • 關閉resister_global和magic_quotes_*
  • 關閉expose_php
  • 關閉 always_populate_raw_post_data 除非你必須使用它
  • 非命令行模式下請關閉register_argc_argv
  • 只在.php文件中使用PHP
  • 優化max_execution_time, max_input_time, memory_limit與output_buffering的參數
  • 將Apache配置文件中allowoverride設置爲none提高文件/目錄的訪問速度
  • 使用-march, -mcpu, -msse, -mmmx, and -mfpmath=sseto使CPU最優化
  • 使用MySQL原生驅動(mysqlnd)替換libmysql、mysqli擴展以及PDO MYSQL驅動
  • 關閉 register_globals、register_long_arrays以及register_argc_argv. 開啓auto_globals_jit.

其餘(Other)

還有些技巧比較難歸類:

  • 使用include()、require(),避免使用include_once()和require_once()
  • 在include()/require()中使用絕對路徑
  • 靜態HTML被PHP生成的HTML要快
  • 使用ctype_alnum、ctype_alpha以及ctype_digit代替正則表達式
  • 使用簡單的servlets或CGI
  • 代碼在產品環境中使用時,儘量寫日誌
  • 使用輸出緩衝
  • 請使用isset($a)代替比較$a==null;請使用$a===null代替is_nul($a)
  • 須要腳本開始執行時間,請直接讀取$_SERVER[’REQUEST_TIME’],而不是使用time()
  • 使用echo替代print
  • 使用前自增(++i)代替後自增(i++),大多數編譯器如今都會優化,可是他們不優化時,請保持這樣的寫法。
  • 處理XML,使用正則表達式代替DOM或者SAX
  • HASH算法:md4, md5, crc32, crc32b, sha1比其餘的散列速度都要快
  • 使用spl_autoload_extensions時,文件擴展名請按最經常使用–>最不經常使用的順序,儘可能排除掉壓根不用的。
  • 使用fsockopen或fopen時,使用IP地址代替域名;若是隻有一個域名,使用gethostbyname()能夠獲取IP地址。使用cURL速度會更快。
  • 但凡可能,用靜態內容代替動態內容。
相關文章
相關標籤/搜索