PHP 板


LINE

看板 PHP  RSS
小弟花了很長的時間 才稍微搞懂Composer、namespace、PSR-0 希望這篇文章能幫一些人節省時間 <(_ _)> 網頁好讀版 http://blog.turn.tw/?p=1122 ----------------------------------- 上次的Composer設計原理與基本用法說明了PHP套件管理的歷史與社群提出的解決之道,本 篇文章接著談類別管理的進階議題。 當類別名稱一樣… 當專案大了起來,有時候會有類別名稱重複的問題。 假設今天要撰寫一個論壇模組,提供討論區與留言板功能。 你一定很想將討論區的文章與留言板的文章都命名類別為Article: // BoardArticle.php <?php class Article{ //... } // ForumArticle.php <?php class Article{ //... } 當然了,這麼做會得到一個結果: Fatal error: Cannot redeclare class Article 這種問題有一個簡單的解決辦法,就是加上前綴字。 類別分別命名為ForumArticle與BoardArticle就可以了。 Q1: 等一下!這個解法好陽春!我看到至少4個問題: 1. 類別名稱容易變得冗長。 2. 有些類別一開始你以為不會跟人重複,結果之後真的重複了。 難道永遠替類別加前綴字? 3. 類別名稱寫Article俐落多了!文章就是概念上的文章,不要逼我告訴你是討論區 還是留言板!如果專案用到兩種留言板模組,分別由以前的兩個前輩寫好, 難道還要逼我把作者名稱寫進去? class TonyBoardArticle{ //... } class JackBoardArticle{ //... } 4. 如果我在打造框架(framework)呢?幾乎會把所有常見名詞用過一次(像是Request、 Loader、Response、Controller、Model等類別)! 難道前面全部前綴?看看Codeigniter的原始碼,全部用CI_當作前綴。超醜的。 命名空間(namespace)登場 於是PHP從5.3版之後支援了命名空間(namespace)。 所以可以用Article替類別定義了: // BoardArticle.php <?php namespace Board; class Article{ //... } // ForumArticle.php <?php namespace Forum; class Article{ //... } 使用類別時只要加上命名空間即可: //index.php <?php include 'BoardArticle.php'; include 'ForumArticle.php'; $article = new Forum\Article(); $post = new Board\Article(); 如果當前的php檔只用到其中一個Article類別, 可以指定當前的php檔只用哪個命名空間+類別的組合: <?php include 'BoardArticle.php'; include 'ForumArticle.php'; use Forum\Article; $article = new Article(); $fArticle = new Forum\Article(); $bArticle = new Board\Article(); 如此一來,當php找不到Article類別時,便會去使用use關鍵字宣告的組合。 當然了,就算用use指定過,原本的宣告方式還是可以用的。(如最下方兩行所示) 當東西多了起來… OK,可以繼續完成我們的論壇模組了! 討論區跟留言板有各自的文章,再來還需要「推文」: <?php namespace Board; class Comment{ // ... } <?php namespace Forum; class Comment{ // ... } 使用剛剛學到的命名空間去載入他們: <?php // index.php include 'BoardArticle.php'; include 'ForumArticle.php'; include 'BoardComment.php'; include 'ForumComment.php'; $article = new Forum\Article(); $comment = new Forum\Comment(); // ... 果然是漂亮的各種命名阿! Q2: include有好多行!上次的Composer設計原理與基本用法提到了Composer可以解決這種 問題,當引入命名空間之後,Composer也能發揮作用嗎? 是的。 Composer登場 跟上次初學Composer一樣,建立一個composer.json檔: { "autoload": { "files": [ "ForumArticle.php", "ForumComment.php", "BoardArticle.php", "BoardComment.php" ] } } 注意,上次我們用”classmap”指定資料夾、把資料夾內檔案全掃一次,這次我們用” files”分別設定各個檔案。 再來,在terminal輸入 composer install 執行完畢之後,跟上次一樣,只要載入一個檔案: <?php require 'vendor/autoload.php'; $article = new Forum\Article(); $comment = new Forum\Comment(); 就可以使用各個類別囉! Q3: 等一下!看起來跟沒有命名空間的時候差不多啊! 一樣是把php檔自動require進去而已? 對啊,你最上面的原始寫法,也只是手動載入好幾個檔案, 在載入的時候本來就沒有特別之處: <?php // index.php include 'BoardArticle.php'; include 'ForumArticle.php'; include 'BoardComment.php'; include 'ForumComment.php'; $article = new Forum\Article(); $comment = new Forum\Comment(); // ... 載入php檔就只是載入,跟命名空間是兩回事。 Q4: 還是不太對啊!上次我用classmap一次把好幾個資料夾內容掃過,這次我用files分別 指定每個檔案幹嘛?Composer不是厲害在能指定資料夾去自動掃過? ……你說的沒錯。 開個my_lib資料夾,把4個php檔都丟進去吧。composer.json這樣寫就好了: { "autoload": { "classmap": [ "my_lib" ] } } 再來,在terminal輸入 composer install 這樣就搞定了! 其實我只是想示範,除了用classmap設定資料夾之外,也可以用files直接指定檔案。 Q5: OK,原諒你。不過,我必須說,我今天什麼都沒學到。最後還是在composer.json寫 classmap而已,跟上次一模一樣。 是的…我剛說了,載入php檔就只是載入,跟命名空間是兩回事。 我今天介紹的namespace功能是PHP本身提供的。而Composer只是協助你載入的工具、 當然不可能改變程式語言本身。 Composer只是幫助你少打那一串require而已。 Q6: ㄟ等等…有個地方我覺得很醜。我們現在的my_lib資料夾裡面有4個檔案,檔名很醜: "ForumArticle.php" "ForumComment.php" "BoardArticle.php" "BoardComment.php" 類別名稱本身都是俐落的Article跟Comment了,檔案名稱還是有前綴字。 但也不可能有兩個Article.php、兩個Comment.php。你有沒有辦法解決這個美感問題? 這個問題簡單,把那個my_lib資料夾刪掉,開一個Forum資料夾、一個Board資料夾。 本來的ForumArticle.php改成Article.php丟進Forum資料夾、 本來的BoardArticle.php改成Article.php丟進Board資料夾。 composer.json改寫成這樣: { "autoload": { "classmap": [ "Board", "Forum" ] } } 再來,在terminal輸入 composer install 這招不錯吧!檔案名稱就是類別名稱,乾淨俐落! 而且資料夾的名字本身就是namespace的名稱! 以後都這樣做啦!一用到命名空間就開個同名資料夾把檔案丟進去! Q7: 這招我覺得還好耶…。本來檔案都放在my_lib,我在composer.json只要填my_lib一行 就好,現在變成要填兩行。要是我這個論壇模組有一大堆類別、用了一大堆命名空間呢? 那我classmap底下不就要填入好幾行?那我寧可全部丟進my_lib,只填my_lib一行! 唔,這樣說也是有道理。那重新建立my_lib資料夾,把Board跟Forum資料夾丟進 my_lib資料夾。composer.json改回這樣寫: { "autoload": { "classmap": [ "my_lib" ] } } 再來,在terminal輸入 composer install classmap不只是告訴Composer去載入哪幾個資料夾內的檔案,還會把資料夾內的 資料夾也全部掃過一次。 怎麼樣,Composer夠神吧。 Q8: 原來classmap底下會遞迴掃描下去…。我決定了,我的Forum跟Board都是在 提供線上討論功能,我決定替我這個模組命名為Discussion。 我要在my_lib底下開Discussion資料夾,然後把原本的Forum跟Board資料夾都丟進去。 你覺得這個想法如何? 還不錯。一個Discussion資料夾就是你的整個Discussion模組。 提供了討論區、留言板功能的Discussion模組,我喜歡。 Q9: 好像忘了什麼…。啊,剛剛說命名空間跟檔案結構符合會最漂亮。那我要把那4個檔案 的namespace改成這樣: <?php namespace Dicussion/Forum; class Article{ //... } 剛剛說了,載入檔案就只是載入檔案,跟命名空間無關。 現在檔案結構沒變,所以我應該不用重新輸入composer install。 讓我試試…。 靠!怎麼噴error了!你騙我? Fatal error: Class 'Discussion\Forum\Comment' not found 呃…,我前面的說法確實有點誤導。 PHP自動載入的基本函式長這樣: void __autoload ( string $class ) 如你所見,PHP至少需要Composer提供資訊指出$class該去哪個檔案找。 namespace改變之後,PHP會找不到對應的$class在哪。 所以還是輸入一下composer install吧!Composer會把需要的資訊整理好的。 Q10: OKOK,我知道了,我駕馭這一切了。我覺得這個Dicsussion模組真的超屌的, 不但命名空間漂亮,連檔案結構都漂亮。 我要把這個Discussion資料夾整個丟給我朋友,他們公司最近需要論壇模組。 讓我打電話給他…。 「什麼?你們已經做好半個論壇模組了?你只需要我模組的其中幾個功能? 你們的模組也是放在Discussion資料夾?」 糟糕,資料夾名稱重複了!所以我的模組拿給別人還是有不相容的可能,怎麼辦? 沒有錯..還記得你Q1提到的第3個狀況嗎?確實有把作者名稱加進去的必要! 別怕,我教你。你開一個Tony資料夾,把整個Discussion資料夾丟進去。 接著所有檔案namespace改成像這樣: <?php namespace Tony/Dicussion/Forum; class Article{ //... } 要用的時候就這樣喔: <?php require 'vendor/autoload.php'; $article = new Tony\Discussion\Forum\Article(); $comment = new Tony\Discussion\Forum\Comment(); 是變得有點長啦。 但這下搞定了吧!作者名稱再撞到的話,就改個獨特的名稱就是了! 終於。讓我們談談PSR-0 你一定常聽到PSR-0對吧! PSR-0是PHP跨框架相容性統一標準組織訂出來的自動載入慣例。 來談談PSR-0幾個最重要的要求吧! * 命名空間加上類別名稱一定要長這樣: \<Vendor Name>\(<Namespace>\)*<Class Name> * 前面一定要是作者名稱 * 中間可以有任意層次的命名空間、最後是類別名稱。 * 中間任意層次的命名空間直接對應到檔案結構。 發現了嗎?在剛剛Q1~Q10的過程中,其實你已經把PSR-0學完了, 連設計原理都一起搞懂了。 懂這些之後,你也可以做好自己的模組、發佈到Packagist給全世界 透過composer下載、使用了! 最後,如果遵守psr-0的話,composer.json可以這樣寫: { "autoload": { "psr-0": { "Tony\\Discussion\\": "my_lib/" } } } 注意,雙引號、兩次反斜線並沒有特別意思,只是json規定的格式。 跟classmap一樣都可以完成任務。兩者其實是有差別的…,我們下次再談。 結語 Composer工具以及PHP-FIG組織的出現, 讓一直以來散落各地的PHP社群開始有集中的趨勢。 換句話說,各社群終於能共享彼此的library了。 然而,如你所見,psr-0不但導致檔案結構容易變得深層,還要求檔案結構必須配合程式碼 ,這也招致了不少批評。 除此之外,composer autoload內的classmap跟psr-0到底如何分工? 效能差異又為何?這些問題也都還在爭論與驗證當中。 不過,PSR-0在各框架已被廣泛支援,因此建議你還是需要有所瞭解。 最後… 現在已經出現psr-0的替代方案,稱為psr-4。 PSR-0從2014-10-21開始被註明為不建議使用。 至於PSR-4..我們下次再談。 --



※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 118.160.223.112
※ 文章網址: http://webptt.com/m.aspx?n=bbs/PHP/M.1418226146.A.0AE.html
1F:推 yoyotvyoo: 推 12/10 23:48
2F:推 rickysu: 推 12/11 09:00
3F:推 lucky1lk: 推推 12/11 09:31
4F:推 DJake: 推推推推推 12/11 09:43
5F:推 onininon: 推 12/11 09:51
6F:推 shooliss: 推 12/11 22:20
7F:推 LPH66: 題外話, 其實這種 namespace 的命名規則也是 java package 12/12 09:01
8F:→ LPH66: 建議的命名方式, 因為這些都是可以到處 deploy 的東西 12/12 09:02
9F:→ LPH66: 因此定出來的規則也就大同小異 12/12 09:02
10F:推 aoeeoak: 推,用心寫的易於消化 12/13 14:55
11F:推 GTim: 推!有在用,但不是很熟悉…… 12/15 04:23
12F:推 taikobo: 推,問答的方式很活潑,讓我想到 Head First 系列 12/16 11:46
13F:推 serinasky: 推 02/23 02:17







like.gif 您可能會有興趣的文章
icon.png[問題/行為] 貓晚上進房間會不會有憋尿問題
icon.pngRe: [閒聊] 選了錯誤的女孩成為魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一張
icon.png[心得] EMS高領長版毛衣.墨小樓MC1002
icon.png[分享] 丹龍隔熱紙GE55+33+22
icon.png[問題] 清洗洗衣機
icon.png[尋物] 窗台下的空間
icon.png[閒聊] 双極の女神1 木魔爵
icon.png[售車] 新竹 1997 march 1297cc 白色 四門
icon.png[討論] 能從照片感受到攝影者心情嗎
icon.png[狂賀] 賀賀賀賀 賀!島村卯月!總選舉NO.1
icon.png[難過] 羨慕白皮膚的女生
icon.png閱讀文章
icon.png[黑特]
icon.png[問題] SBK S1安裝於安全帽位置
icon.png[分享] 舊woo100絕版開箱!!
icon.pngRe: [無言] 關於小包衛生紙
icon.png[開箱] E5-2683V3 RX480Strix 快睿C1 簡單測試
icon.png[心得] 蒼の海賊龍 地獄 執行者16PT
icon.png[售車] 1999年Virage iO 1.8EXi
icon.png[心得] 挑戰33 LV10 獅子座pt solo
icon.png[閒聊] 手把手教你不被桶之新手主購教學
icon.png[分享] Civic Type R 量產版官方照無預警流出
icon.png[售車] Golf 4 2.0 銀色 自排
icon.png[出售] Graco提籃汽座(有底座)2000元誠可議
icon.png[問題] 請問補牙材質掉了還能再補嗎?(台中半年內
icon.png[問題] 44th 單曲 生寫竟然都給重複的啊啊!
icon.png[心得] 華南紅卡/icash 核卡
icon.png[問題] 拔牙矯正這樣正常嗎
icon.png[贈送] 老莫高業 初業 102年版
icon.png[情報] 三大行動支付 本季掀戰火
icon.png[寶寶] 博客來Amos水蠟筆5/1特價五折
icon.pngRe: [心得] 新鮮人一些面試分享
icon.png[心得] 蒼の海賊龍 地獄 麒麟25PT
icon.pngRe: [閒聊] (君の名は。雷慎入) 君名二創漫畫翻譯
icon.pngRe: [閒聊] OGN中場影片:失蹤人口局 (英文字幕)
icon.png[問題] 台灣大哥大4G訊號差
icon.png[出售] [全國]全新千尋侘草LED燈, 水草

請輸入看板名稱,例如:Tech_Job站內搜尋

TOP