Symfony2是一個基於PHP語言的Web開發框架,有着開發速度快、性能高等特色。但Symfony2的學習曲線也比較陡峭,沒有經驗的初學者每每須要一些練習才能掌握其特性。相對其餘框架,Symfony2比較吸引人的特色有: php
本文經過對一個基於Symfony2框架所開發的網站頁面進行逐步優化,最終實現頁面加載速度的提升的例子,向讀者介紹Symfony2框架的一些 核心功能和特色。經過閱讀本文,你能夠經過一些具體的例子瞭解Symfony2框架的優秀特性和技術特色,從而體會到使用Symfony2框架能夠爲網站 開發帶來的各類優點。 css
在我所演示的項目中,已經包含了一個頁面,經過輸入這個地址來打開它:http://your.host.com/appdev.php/testpage_1。出現的頁面以下圖所示: 前端
咱們打開瀏覽器自帶的調試功能,而後刷新頁面: java
相關廠商內容 web
能夠看到,該頁面充斥着大量的js/css/圖片文件,而整個頁面的加載速度居然達到了9.6秒。 編程
而若是打開這個頁面:http://your.host.com/app.php/testpage1,出現的頁面以下圖所示: 後端
咱們發現頁面的加載速度變成了4秒,同時衆多js和css文件被各自合併成爲了兩個單獨的文件(圖中紅框的部分)。 瀏覽器
形成上面兩個頁面打開速度大相徑庭的緣由在於:若是經過不一樣的入口文件(app.php和appdev.php)進入頁面,Symfony2會根據入口文件的不一樣,切換到不一樣的運行環境。好比在默認配置中:經過app.php訪問的頁面,就是生產環境,而經過appdev.php訪問的頁面,則是開發環境。 Symfony2根據運行環境的不一樣,運行程序時的配置也會不一樣。好比細心的讀者可能會發現,開發環境中頁面的下方多了一條像是工具欄同樣的東西(這是 Symfony2特有的開發調試欄)。環境的不一樣會影響Symfony2程序運行的各個環節,如下列舉了一些比較重要的不一樣配置下的差別處:
功能 | 開發環境 | 生產環境 |
----- | ----- | ----- |
開發調試欄 | 會出現 | 不會出現 |
日誌記錄 | 記錄詳細的程序執行信息 | 只在程序出現錯誤的時候記錄 |
css/js合併 | 不會 | 會 |
因此能夠看出,css/js文件合併實際上是Symfony2自動根據環境不一樣所開啓或關閉的一個自帶功能罷了,這個功能在Symfony2中叫作Assets管理,固然咱們也能夠經過控制入口文件來實現開啓或者關閉其餘更多的功能。
經過Symfony2的環境配置功能開啓或關閉各類自帶功能就像在文本里改一個參數那麼簡單,而每一個不一樣的環境又有一套獨立的環境配置。 Symfony2提供了大量的參數供用戶方便的配置各類功能,經過對不一樣環境下的各個功能進行配置,能夠很方便的設置出一套適合你本身的工做/生產環境。
接下來讓咱們看看Assets管理模塊還能爲咱們作什麼。
經過對上述頁面的分析,咱們發現雖然js和css文件合併了,但各自的文件內容卻沒有通過壓縮,兩個文件的大小分別是437k和310k,這顯然是一個不太合理的數字。但咱們能夠經過簡單的配置,讓Assets管理模塊幫咱們在合併文件的同時對內容也進行壓縮。
例如咱們選擇使用uglifyjs2對js進行壓縮,用yuicompressor對css進行壓縮。在這些軟件已經安裝完畢的狀況下,只須要修改app/config.yml的如下幾行:
assetic: debug: "%kernel.debug%" use_controller: false bundles: ['ScourgenHFS2Demo1Bundle'] java: /usr/bin/java filters: cssrewrite: ~ uglifyjs2: compress: true mangle: true bin: /opt/local/bin/uglifyjs yui_css: jar: /usr/share/yuicompressor-2.4.7.jar
而後在layout模板中引入js/css的地方分別增長一個過濾器
'@ScourgenHFS2Demo1Bundle/Resources/public/css/public_home.css' '@ScourgenHFS2Demo1Bundle/Resources/public/css/inner_city_line.css' filter='?yui_css' %} <link rel="stylesheet" type="text/css" media="screen" href="{{ asset_url }}" /> ... '@ScourgenHFS2Demo1Bundle/Resources/public/js/common/title.js' filter='?uglifyjs2' %}
咱們再執行一下生成Assets的命令:
% php app/console assetic:dump --env=prod Dumping all prod assets. Debug mode is off. 03:14:06 [file+] /Users/scourgen/Desktop/InfoQ/ optimize_performance_of_pages_with_symfony2/HeadFirstSymfony2-Demo1/app/../web/css/2ff013f.css 03:14:14 [file+] /Users/scourgen/Desktop/InfoQ/
而後再打開剛纔生產環境下的頁面,這時會發現剛纔的兩個css和js文件的大小已經變成了271k和232k,文件內容也已經都變成了通過 uglifyjs2和yuicompressor壓縮以後的內容。雖然兩個文件大小依然很大,但若是考慮到它們在通過gzip壓縮後的文件大小隻有86k 和39k,也應該算是在合理範圍以內了。
固然在實際開發中,咱們常常會碰到雖然服務端的js/css文件內容修改了,但客戶端卻保留着舊版本的緩存,致使頁面樣式和js功能出現問題的狀況,而爲了解決這個問題,一樣能夠經過修改配置實現:
#app/config.yml #將framework的templating改爲以下的樣子: … templating: assets_version: 1 assets_version_format: %%s?%%s engines: - twig assets_base_urls: http: - http://server1.dev - http://server2.dev ...
而後爲css合併文件指定一個文件名:
'@ScourgenHFS2Demo1Bundle/Resources/public/css/public_home.css' '@ScourgenHFS2Demo1Bundle/Resources/public/css/inner_city_line.css' filter='?yui_css' output='css/a.css' %}
咱們再刷新一下頁面,看看發生了什麼。
這時剛纔兩個js和css的URL分別變成了:
雖然js和css文件的url後面都帶上了一個變量(也就是上面所定義的assets_version),而因爲URL的不一樣,客戶端將會從新下載這兩個文件以免從緩存中讀取舊的版本。但爲何這兩個文件的地址會變成serverx.dev呢?
其實這是Assets管理模塊的另一個功能:將它所管理的文件路徑變成絕對地址(也就是增長了上面配置文件中的 http://server1.dev和http://server2.dev兩個域名)。並且在配置了多個域名的狀況下,哪一個文件名匹配哪一個域名是固定 的,不會隨機顯示形成帶寬浪費,而這實際上是由它的一套算法實現的。
經過這樣的修改,咱們也獲得了兩個益處:
相似的狀況也有不少,在開發中爲了實現最佳實踐咱們每每須要絞盡腦汁,但若是使用Symfony2做爲開發框架則會使問題變得很是簡單,甚至簡單到根本不用寫代碼,只須要更改幾行配置就能實現。
話說回來,在通過這些調整以後,前端的載入速度看起來已經不錯了。那麼Symfony2是否也能夠很方便的調試和優化後端代碼?答案是確定的。接下來咱們看一下如何使用Symfony2調試和優化程序的性能。
調試和優化程序的最基本前提就是:你得知道你的程序在幹什麼。這句話雖說得輕巧,但在許多框架面前卻很難作到。這些框架在各類高新技術的封裝下, 代碼和程序邏輯也變得十分複雜和臃腫,想要得知你所使用的框架背後到底作了哪些具體的事情、或者想獲取程序運行的堆棧和調用信息、以及 MySQL/NoSQL/MessageQueue……這些服務的調用和執行狀況等等,都是不太容易的。而在沒有這些信息支持的狀況下,想去對後端程序作 調試和優化幾乎是不可能的。
而獲取這些信息以便進行開發和優化對於Symfony2來講卻很是容易,緣由有三個:
上圖是一個顯示程序執行順序以及耗時的界面,經過這個界面,開發者能夠很直觀的看到程序的詳細執行流程和順序。經過這個界面,也能夠看到每一個步驟所 佔用的時間,從而發現影響程序執行速度的瓶頸,從而有針對性的進行優化。好比上圖所示的程序執行流程裏,一眼就能看出一共有三個地方執行的時間比較久(青 色的條比較長)。
高效且合理的框架設計使得Symfony2框架內的每一個模塊都不互相耦合, 每一個模塊都有本身的職責,能夠單獨爲其執行測試用例而不依託其餘模塊。每一個模塊也都會像一個獨立的軟件同樣有其本身的版本發佈週期,有的模塊甚至擁有獨立 的維護團隊。這樣的設計讓Symfony2取得了複雜性和擴展性之間的平衡,也完成了架構上的解耦,從而直接在架構層面下降了整個框架的複雜度。因此對於 開發者來講,不管是開發新功能,仍是優化現有程序,都會以爲很是方便和高效。
日誌記錄功能把框架在執行時的全過程都完徹底全記錄在了日誌中,你惟一須要擔憂的就是及時清理日誌以避免磁盤空間佔用過大。下圖是日誌的一部分,能夠看到日誌所記錄的信息是很是詳細的,讓人不由聯想起了一些重量級Java框架的日誌的輸出。
因此綜上三點所述,Symfony2對於調試和優化是很是友好的,利用其自帶功能和設計能夠很方便的進行調試和優化。
Symfony2自己已經作得很是出色了,那麼在Symfony2以外呢?
雖然你們在國內可能不太聽獲得Symfony2這個名字,但在國際市場上Symfony2但是很是出名的。許多IDE軟件開發商都支持 Symfony2(比較出名的有PHPStorm、NetBeans和Eclipse with PDT),經過這些軟件對於Symfony2的支持,可以讓開發者更加方便快捷的進行開發工做。
而對於開源軟件開發者,以及一些大網站的技術團隊而言,他們也圍繞Symfony2框架作了不少工做,也開源了許多他們本身的模塊。在 Symfony2的託管平臺Github上,Symfony2項目的fork量和star量分別爲6428和2174(截止2013年4月中旬),位居所 有PHP項目的前列。而在最近發佈的對2.2版本的開發統計顯示,共有2035次提交以及711次申請合併,平均天天11次提交和4次申請合併。如此頻繁 的代碼變動速度也能證實Symfony2以及相關社區的活躍度。
有如此強大的開發工具和社區支持,無論開發者在碰到什麼問題時,基本上均可以迎刃而解。固然就算碰到了比較複雜的難題,也能夠在Symfony2的社區或IRC頻道中詢問其餘開發者。固然也能夠來找我,個人聯繫方式在本文最下面。
對於優化程序性能來講,通常會有三個方向:
代碼語法的優化並不是本文的主題,而業務邏輯則又是由具體的網站功能所決定的,並不會有什麼放之四海皆準的辦法,因此本節主要介紹的是如何更加高效的使用Symfony2框架所附帶的功能來提升網站的響應速度。
下面介紹一下Symfony2中最重要的優化功能之一 - 頁面緩存功能。
對於一個頁面來講,常常會有多個程序塊來負責分別處理不一樣的頁面部分,好比上文咱們所展現的這個頁面中,可能會有一塊程序來處理頁面上方的黑色導航 條:顯示全部的公交信息及判斷用戶所在地點;一塊程序來處理頁面的中間部分:根據用戶是否登陸顯示不一樣的內容;一塊程序來處理頁面下方的線路詳情信息;而 這個頁面的最終內容其實就是頁面樣式模板加上這三個程序輸出後的結果。若是但願加快頁面速度,最好的辦法就是加快這三個程序的輸出結果,甚至將結果緩存起 來以便從此直接調用。
那咱們看看如何對頁面進行緩存,下面我將經過一個例子來向讀者展現如何作到這點。
使用頁面片斷緩存,咱們先要在包含其餘頁面片斷的代碼上增長一個standalone參數:
{% render url('layout_top', {}) with {}, {'standalone': true} %}
而後在這個處理頁面片斷的方法上配置緩存信息。
/** * @Route("/esi/getTop", name="layout_top") * @Cache(public=true,expires="+1 hour", smaxage=3600, maxage=3600) */
能夠看到經過配置,咱們爲這個頁面片斷定義了一小時的過時時間,定義緩存的參數和HTTP頭信息中控制緩存的參數是相同的(public,expires,maxage等)。
細心的讀者會發現兩個問題:
其實經過回答這兩個問題,讀者能夠理解Symfony2框架的另外兩個重要功能:
Annotation這個單詞是「註釋」的意思,在編程開發領域特指一種編程語言可以經過註釋來改變程序的運行邏輯。對於熟悉其餘語言的讀者來 說,Annotation其實並不陌生,好比在Java裏就有各類Annotation,@Override和@GuardedBy等你們也都比較熟悉。 Annotation對於開發者來講可以大大的簡化程序的複雜度:把複雜的程序邏輯抽象成爲參數配置。可是對於PHP來講,PHP語言實際上是不支持 Annotation這個功能的,因而Symfony2在其框架內部實現了Annotation:第一次執行程序時,Symfony2會自動分析處理源文 件,並將結果緩存在文件系統中,下次程序再被執行時,Symfony2會自動執行上次生成的文件,從而避免每次都對源文件的註釋進行分析,而整個過程對開 發者來講是徹底透明的(這也能解釋爲何有些頁面第一次打開會比較慢,但之後就會很快)。
Symfony2框架中大量使用了Annotation:從緩存的定義到路由的配置,甚至到表結構的定義,到處都使用了Annotation功能。 你甚至能夠根據規範編寫本身的Annotation。因此在使用Symfony2開發程序時,複雜的邏輯會變成一行行清晰的註釋,程序的流程控制將變得非 常簡單。
而對於頁面緩存功能來講,Symfony2有一個模塊實現了兼容ESI協議的反向代理功能,從而容許開發者使用HTTP協議來控制頁面緩存以及設置 過時時間等,因此在網站規模變大的時候,開發者也能夠平滑地將自帶的反向代理模塊升級成專門的反向代理服務(例如使用Varnish),從而提高網站總體 性能。
對於不太熟悉ESI的讀者,我在這裏稍微作一下解釋:
ESI是經過代理服務對頁面片斷進行訪問的一種協議,好比你的HTML代碼中有一段ESI:
<esi:include src="/top" max-age="45"/>
那麼當ESI服務軟件(例如Varnish)獲取到包含這行代碼的HTML以後,會當即向"/top"這個URL作一個額外的HTTP請求,同時把 這個請求的HTML返回數據填充在這個頁面裏。假設"/top"的返回數據是一段A標籤,那麼上文的這段HTML代碼在顯示給用戶的時候,就變成了:
<a href="http://for_example.com">for_example.com</a>
固然ESI的功能遠不止那麼簡單,咱們在此主要用到的是它的頁面片斷緩存功能。
做爲一個成熟的Web開發框架,對數據庫操做的支持天然是重中之重,Symfony2對於這塊天然也不例外。Symfony2默認使用 Doctrine2做爲其ORM的實現,經過Doctrine2,用戶能夠像操做一個類同樣去操做數據庫,從而提升開發效率。ORM這個概念讀者應該都不 陌生,在其餘語言裏也有各類實現,但在使用ORM上咱們常常遇到這樣的挑戰,即如何權衡數據庫性能和開發效率之間的平衡:
那Doctrine2又是如何解決這些問題的呢?咱們經過一個比較有特點的例子來感覺一下:
$user=$this->getDoctrine()->getRepository('ScourgenHFS2Demo1Bundle:User')->find(2) echo $user->getName();
在上面這段代碼中,第一行雖然看起來是向User表去查詢ID爲2的用戶,但其實尚未任何SQL語句在數據庫上執行,$user就是一個上文所提 到的代理對象。而當在第二行中,當這個對象的屬性第一次被調用的時候,真實的SQL語句纔會被傳遞到服務器,而且將結果集中的name字段返回給echo 函數。
形成以上現象的緣由是Doctrine2支持延遲加載功能:當程序執行對數據庫的操做時,好比獲取一條條數據,返回的對象並非一個真實的來自數據 庫的結果集,而是一個代理對象(Proxy Object),而只有當數據被真正調用的時候,這個代理對象纔會去數據庫裏進行查找,並返回真實的數據。
因此使用延遲加載的好處是:ORM會根據真正須要的內容去獲取相應的數據。
想象一下若是你的表結構很是複雜,並且前端頁面常常改變,在這種狀況下通常都須要對SQL操做進行必定的修改和重構才能知足不斷變化的需求,並且很 難保持性能的最優化。而若是此時有延遲加載功能,就可以保證無論頁面如何變化,數據庫操做相關的代碼均可以在不須要修改的前提下,一直生成最優化的SQL語句去獲取那些真正被使用到的數據。因此延遲加載纔可以一方面顯著的加快開發速度,一方面優化頁面性能。
固然除此以外Doctrine2的功能還有不少,包括批量處理、對象生命週期管理、表結構自動維護等等,Doctrine2也能夠做爲一個單獨的類 庫被Symfony2以外的程序所使用。但在這裏因爲主題和篇幅的限制,我不作過多的介紹,若是讀者們對此感興趣的話,但願之後可以有機會單獨寫文介紹。
本文向你們展現了Symfony2的一些很酷的功能,從Symfony2的環境設置,到Assets管理,到開發調試欄的介紹,再到緩存優化的分 析……讀者能夠經過上面的幾個例子感覺到使用Symfony2做爲框架進行開發並非一件很複雜的事情:改幾行配置,甚至都不須要寫代碼,就可使用業界 的各類「最佳實踐」來解決問題。就讓框架作應該作的事情吧,分工明確才能讓開發者可以安心的把注意力集中在本身項目的業務邏輯上,從而提升項目的速度和質 量。
而在國內,因爲框架輩出,甚至有幾年開發經驗的工程師甚至都會本身作一個框架,社區和業界也缺乏一個公認的答案和方向:工程師都在打一槍換一個地 方,而各大公司和團隊都在重複製造各類不一樣樣子的輪子,整個業界的風氣也變得異常浮躁,以致於許多人索性放棄了對完美的追求,直接認可了他們作的事情就是 「quick and dirty「的。
我並不期望可以改變你的想法,但若是你也有一些相同的感悟,那麼請嘗試一下Symfony2,它將幫助你從新找回信心。
洪濤在互聯網、零售、電信領域有多年的從業經驗,曾負責中國電信域名糾錯平臺的開發,也曾爲雅虎、騰訊等大型互聯網站進行架構設計與開發工做,他善 於使用開源技術解決技術難題,做爲一個87年生的人,他有着「洪大師」的稱號。洪濤目前的興趣是Symfony2框架在中國的推廣和普及。