恭喜你!經過學習Symfony2,你將用你本身的方式開發出更加高效、全面和流行的Web應用(固然,要受到用人單位或同行的歡迎,仍是得靠你本身)。Symfony2的存在是爲了要解決最根本的問題:即提供一個開發工具,使開發者能以本身的方式更快速地開發出更爲健壯的應用程序。Symfony2集成了許多技術的優勢,包括工具和概念,你將學到大多數人多年來努力的方向。換句話說,你不僅是在學習Symfony2,你還將學習Web基礎原理、最佳開發實踐以及如何使用許多新的、優秀的PHP開發庫。因此,請作好準備!
php
本章將從解釋Web開發過程當中最常接觸的基礎概念開始:HTTP協議。不管技術背景或首選編程語言是什麼,本章的內容對於全部人來講都是必需要了解的。html
HTTP(超文本傳輸協議)是一個容許兩個機器相互通訊的文本語言。舉例來講,當你要去 xkcd 網站查看最新的漫畫時,下列會話(近似地)將在你的瀏覽器和服務器之間發生:前端
雖然實際使用的語言將更加正規,但它依然是很簡單的。HTTP定義了這種簡單文本語言的語義和語法。而不管你從事何種的Web開發,你的服務器老是要理解基於文本的請求,並返回基於文本的響應。git
Symfony2是基於現實構建的,不管你是否意識到這一點,HTTP都是你天天所需的。隨着對Symfony2學習的深刻,你將學會如何掌握它。github
Web上的每一個會話都是從一個請求開始的,這個請求是由客戶端(如:網頁瀏覽器、iPhone應用程序等)建立的一種特殊格式的文本消息,該格式符合HTTP協議規範。客戶端將該請求發送到服務端,而後等待服務端響應。數據庫
下圖體現的是,瀏覽器與xkcd服務器之間交互的第一階段(請求):編程
以HTTP的方式來講,HTTP請求就象下面這個樣子:數組
GET / HTTP/1.1 Host: xkcd.com Accept: text/html User-Agent: Mozilla/5.0 (Macintosh)
這個簡單的消息準確地描述了客戶端所請求的究竟是哪一個資源。HTTP請求的第一行是最重要的,它包含了兩項信息:URI和HTTP方法。瀏覽器
URI(如:/、/contact等)代表了客戶端所請求資源的惟一地址或位置。HTTP方法(如:GET)則是向服務器說明你想對資源作什麼,HTTP方法是請求的「動詞」,用以定義你對資源的操做:緩存
GET | 從服務器上檢索資源 |
POST | 在服務器上建立一個資源 |
UPDATE | 更新服務器上的資源 |
DELETE | 刪除從服務器上該資源 |
按照這個規則,你能夠發送一條要求刪除指定博文的請求,如:
DELETE /blog/15 HTTP/1.1
註釋:實際上,HTTP協議裏一共定義了9種HTTP方法,但它們中的大部分並無獲得普遍的使用和支持。實際上,許多現代的瀏覽器並不支持PUT和DELETE方法
除了第一行,HTTP請求所包含其餘行的信息被稱爲HTTP請求頭,頭信息還包含:主機、客戶端接受響應的格式、客戶端所用代理的應用程序等。還有許多其它的HTTP請求頭存在,你能夠在維基百科的 List of HTTP header fields 中找到它們。
服務端獲得請求,它就明確地知道客戶端須要哪一個資源(經過URI)以及但願對該資源進行什麼操做(經過HTTP方法)。例如,對於一個GET請求,服務端將準備資源,並在HTTP響應中將其返回給客戶端。如,xkcd服務端返回的響應:
按照HTTP協議的格式,被返回給客戶端的響應以下所示:
HTTP/1.1 200 OK Date: Sat, 02 Apr 2011 21:05:05 GMT Server: lighttpd/1.4.19 Content-Type: text/html <html> <!-- HTML for the xkcd comic --> </html>
HTTP響應包含了客戶端所請求的資源(在這個例子裏是HTML),以及與響應相關的信息。與請求頭相似,第一行也最重要,它給出的是HTTP狀態碼(在 上面的例子裏是200)。狀態碼報告了響應的狀態,如,請求是否成功?是否存在錯誤?不一樣的狀態碼錶示着成功、錯誤或者通知客戶端須要作其它一些事(如重 定向到另外一頁)。完整的列表能夠在維基百科的 HTTP狀態代碼列表 中找到。
全部這些響應信息,組成了響應頭。其中一個重要的HTTP響應頭消息被稱爲Content-Type。服務器上的每一個資源均可以以不一樣的格式返回給客戶端,如HTML、XML或JSON等;經過在Content-Type裏設置如text/html這樣的互聯網媒體類型碼,能夠告知客戶端,服務器給出的響應格式是什麼。常見的媒體類型能夠在維基百科的互聯網媒體類型列表 裏找到。
還存在不少其餘的HTTP響應頭,其中有些能夠起到很重要的做用。好比,某些響應頭能夠用來維護HTTP緩存。
「請求-響應」對話是驅動Web上全部通訊的基礎,它是如此的強大和重要,它又是如此的簡單。
最重要的事實是,無論你使用哪一種開發語言,構建哪一種應用(Web、手機、JSON應用程序接口等),遵循哪一種開發理論,應用程序的最終目標老是一致的:理解每一個請求,建立並返回相應的響應。
Symfony2就是來完成這一「使命」的:
要更瞭解HTTP協議規範,能夠參考 HTTP 1.1 RFC 或者 HTTP Bis (用更直白明瞭方式的來講明HTTP協議規範)。另外,有一款叫作 Live HTTP Headers 的Firefox瀏覽器擴展能夠用來查看上網過程當中請求、響應頭的內容。
那麼,怎麼用PHP來獲知「請求」,並建立「響應」呢?PHP對實際的操做進行了封裝,你要作的,相對還算簡單:
<?php $uri = $_SERVER['REQUEST_URI']; $foo = $_GET['foo']; header('Content-type: text/html'); echo 'The URI requested is: '.$uri; echo 'The value of the "foo" parameter is: '.$foo;
雖然看上去有點奇怪,但這一小段代碼能夠從HTTP請求頭裏提取信息,並依據這些信息建立了響應內容。你並不須要本身寫代碼來解析HTML消息格式,由於PHP爲你準備了一系列的全局變量,如:$_SERVER和$_GET,它們包含了關於請求的全部信息。你還能夠經過調用header()函數來指定響應頭信息;或者用echo一類的語句直接輸出響應裏的正文內容。PHP會負責把你指定的全部信息組成一個有效的HTTP響應,返回給客戶端(注意,中文會通過編碼傳輸)。
HTTP/1.1 200 OK Date: Sat, 03 Apr 2011 02:14:33 GMT Server: Apache/2.2.17 (Unix) Content-Type: text/html The URI requested is: /testing?foo=symfony The value of the "foo" parameter is: symfony
Symfony2使用兩個類能夠很是容易地與請求和響應交互,從而取代原始的PHP方式。Request類是HTTP請求面向對象的簡單表示。有了它,你獲取請求信息將易如反掌。
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 use Symfony\Component\HttpFoundation\Request; $request = Request::createFromGlobals(); // 請求的URI (如:/about) ,沒有任何查詢參數 $request->getPathInfo(); // 分別檢索GET和POST變量 $request->query->get('foo'); $request->request->get('bar'); // 檢索被foo標識的UploadedFile實例 $request->files->get('foo'); $request->getMethod(); // GET, POST, PUT, DELETE, HEAD $request->getLanguages(); // 客戶端接受語言的數組 use Symfony\Component\HttpFoundation\Request; $request = Request::createFromGlobals(); // 請求的URI (如:/about) ,沒有任何查詢參數 $request->getPathInfo(); // 分別檢索GET和POST變量 $request->query->get('foo'); $request->request->get('bar', 'default value if bar does not exist'); // 檢索服務器變量 $request->server->get('HTTP_HOST'); // 檢索上傳文件參數 $request->files->get('foo'); // 檢索cookie的值 $request->cookies->get('PHPSESSID'); // 檢索一個http頭是否是規範化 $request->headers->get('host'); $request->headers->get('content_type'); $request->getMethod(); // GET, POST, PUT, DELETE, HEAD $request->getLanguages(); // 一個獲取語言數組的方法
Request類在後臺所作的大量工做能使你省很多心。如isSecure()方法經過用PHP檢查三個不一樣的值來肯定用戶是否使用了安全連接(經過https)。
ParameterBags 和 Request 類的成員
如上,$_GET 和 $_POST 裏的值能夠經過公有成員query和request來訪問。每個都是 Symfony\Component\HttpFoundation\ParameterBag 類的對象,擁有如下方法: get(), has(), all() 等等。 事實上,上面例子裏提到的公有成員都是ParameterBag的實例。
Request類還有一個公有的 attributes 成員,裏面包含了PHP框架的一些運行數據。Symfony2框架在這個變量裏保存了當前請求所匹配的URL路由,好比_controller,id(若是你使用了 {id} 通配符),甚至當前路由的名稱(_route)。attributes成員實際就是用來保存和提供與當前請求相關的運行環境信息。
Symfony2還提供了一個Response類,一個HTTP響應的簡單PHP表示。這容許你使用面向對象的接口去構建返回客戶端所需的響應。
use Symfony\Component\HttpFoundation\Response; $response = new Response(); $response->setContent('<html><body><h1>Hello world!</h1></body></html>'); $response->setStatusCode(Response::HTTP_OK); $response->headers->set('Content-Type', 'text/html'); // prints the HTTP headers followed by the content $response->send();
symfony新的2.4版:已經支持了引入HTTP狀態代碼
就算Symfony2再沒提供其它工具,你也已經有了能夠輕易訪問請求信息的工具包和用來建立響應的面向對象接口。即便你學了更多Symfony2的功能,也請牢記,你應用程序的目標始終是解釋請求,並根據你應用程序的邏輯建立相應的響應。
Request類和Response類都是Symfony2中名爲HttpFoundation組件的一部分。該組件能夠獨立使用,它還提供處理會話和文件上傳的類。
同HTTP同樣,Request和Response對象也很簡單。應用程序最複雜的部分是在二者之間寫些什麼。換句話說,真正的工做來自於編寫解釋請求並建立響應的代碼。
你的應用程序可能作了諸如發送電子郵件、處理提交表單、向數據庫寫入數據、渲染HTML頁面和確保內容安全性等諸多事情,但你如何來管理這一切,同時還要保持你代碼的組織性和可維護性呢?
Symfony2就是用來解決上述問題,而無須讓你所以分心。
前端控制器
傳統方式中構建的應用程序,網站中的每一「頁」都是它自身的物理文件。
index.php contact.php blog.php
使用這種方式存在幾個問題:不靈活的URL(你是否能夠將blog.php文件更名爲news.php,而無須破壞你全部的連接?)、每一個文件都必須手工包含一些核心文件集以確保安全性(數據庫鏈接和網站外觀必須保持一致)。
更好的解決方案是使用前端控制器:單一的PHP文件,該文件用來處理進入應用程序的全部請求。例如:
/index.php | 執行index.php |
/index.php/contact | 執行index.php |
/index.php/blog | 執行index.php |
使用Apache的mod_rewrite模塊(或其它Web服務器的類似模塊),URL能夠很方便地被清理成諸如:/、/contact、/blog 這樣的連接。
如今,全部請求的處理都徹底同樣。前端控制器將被始終執行,不一樣的URL將被內部路由到你應用程序的不一樣部分,而無須根據不一樣的URL執行不一樣的PHP文件。這樣就解決了前面傳統方式所帶來的問題。幾乎全部現代應用程序均可以作到這一點,其中包括相似WordPress這樣的應用程序。
保持代碼的組織性
前端控制器又是如何知道哪一個頁面要被渲染,如何正確渲染呢?這須要判斷傳入的URI,針對性地調用不一樣的代碼。這也不是容易的差事:
// index.php use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; $request = Request::createFromGlobals(); $path = $request->getPathInfo(); // the URI path being requested if (in_array($path, array('', '/'))) { $response = new Response('Welcome to the homepage.'); } elseif ($path == '/contact') { $response = new Response('Contact us'); } else { $response = new Response('Page not found.', Response::HTTP_NOT_FOUND); } $response->send();
幸運的是,這正是Symfony2被設計來解決的問題之一。
讓Symfony2來處理請求,開發工做就會變得簡單不少。Symfony2在每次處理,都會遵循下面的模式:
你網站的每一頁都被定義在路由配置文件中,在那裏不一樣的URL被映射到不一樣的PHP函數。每一個PHP函數(又名 controller)的工做就是獲得請求的信息(也可使用Symfony2中有許多其它的工具)去建立並返回一個Response對象。
就是這麼簡單,讓咱們回顧一下:
一、每一個請求執行前端控制器文件;
二、根據你的路由配置和請求信息,路由系統決定應該執行哪一個PHP函數;
三、正確的PHP函數被執行,在那裏你的代碼將建立並返回相應的Response對象。
先不考慮太多的細節,舉一個請求處理實例。假設你要在Symfony2應用裏增長一個/contact頁面。首先,修改路由配置文件:
contact: pattern: /contact defaults: { _controller: AcmeDemoBundle:Main:contact }
這個例子使用 YAML來定義路由的配置,你也能夠用XML或PHP來寫。
當有人訪問/contact頁時,該路由條目被匹配,同時執行指定的控制器。
你在 routing chapter 裏將會了解到,AcmeDemoBundle:Main:contact是簡寫法,指向的是MainController類裏的contactAction方法函數。
class MainController { public function contactAction() { return new Response('<h1>聯繫咱們!</h1>'); } }
這個控制器很是簡單,僅僅建立了一個內容爲HTML「<h1>聯繫咱們!</h1>」的Response。參考controller chapter你能夠了解到控制器如何渲染模板,從而使你的「表現層」代碼能夠被寫在單獨的模板文件裏。控制器不須要考慮一些複雜的工做,如:讀寫數據庫,處理由用戶提交的數據,發送電子郵件等。
如今你知道任何應用的目的都是處理傳入的請求,建立相應的響應。當應用程序的規模逐漸增加,要保持代碼的結構和易維護性就變得愈來愈困難。畢竟,有不少事情是你不得不反覆作的:寫數據庫,渲染和重用模板,處理表單提交,發送電子郵件,驗證用戶的輸入和保證安全性。
好消息是,這些事情都不是發射神舟飛船,並不特殊。Symfony2提供了你構建應用所需的幾乎所有工具,因此你能夠專心於創造應用,而不是「從新發明輪子」。Symfony2還有一點值得表揚,就是你能夠選擇是使用整個框架,仍是隻使用它部分的功能。
那Symfony2到底是什麼?首先,Symfony2是一個由20多個獨立的開發庫組成的工具集,你能夠在任何PHP項目裏使用這些代碼。這些開發庫,被稱做Symfony2組件,功能涵蓋了絕大部分的開發需求。舉一些例子:
每個組件都是獨立的,可用於任何PHP項目中,而無論你是否使用了Symfony2框架。它們的每個既能夠在須要時使用,也能夠在必要時被替換。
那麼,什麼是Symfony2框架呢?Symfony2框架是個PHP庫,它實現兩個功能:
這個框架的目標是整合許多獨立的工具,以期給開發人員一致的體驗。甚至就連Symfony2框架自己也是一個Bundle(相似插件),在必要時也能夠被從新配置甚至替換掉。
Symfony2爲快速開發應用程序提供了強大的工具集,普通用戶能夠經過Symfony2的發行版(缺省提供了合理的項目架構)迅速上手,對於更高級的用戶而言,只有想不到,沒有作不到(The sky is the limit.)。