用Composer吧!
理由聽我娓娓道來!
PHP最早讀取套件的方法
初學(xué)PHP時,最早會面對的問題之一就是require與include差別何在?
require_once與include_once又是什麼?
弄懂這些問題之後,如果不使用framework,直接開發(fā),便常出現(xiàn)類似這樣的code:
// whatever.php// 這檔案需要用到幾個類別require 'xxx_class.php';require 'yyy_class.php';require 'zzz_class.php';// ...
然後在其他檔案會出現(xiàn):
// another.php// 這檔案需要用到幾個類別require 'yyy_class.php';require 'zzz_class.php';// ...
這樣的結(jié)果,會產(chǎn)生至少兩個問題:
1. 許多檔案用到同樣幾個class,於是在不同地方都需要載入一次。
2. 當(dāng)類別多了起來,會顯得很亂、忘記載入時還會出現(xiàn)error。
那麼,不如試試一種懶惰的作法?
寫一個php,負(fù)責(zé)載入所有類別:
// load_everything.phprequire 'xxx_class.php';require 'yyy_class.php';require 'zzz_class.php';require 'aaa_class.php';require 'bbb_class.php';require 'ccc_class.php';
然後在其他檔案都載入這支檔案即可:
require 'load_everything.php'
結(jié)果新問題又來了:當(dāng)類別很多的時候,隨便一個web page都會載入一堆code,吃爆記憶體,怎麼辦呢?
__autoload
為了解決這個問題,PHP 5開始提供__autoload這種俗稱「magic method」的函式。
當(dāng)你要使用的類別PHP找不到時,它會將類別名稱當(dāng)成字串丟進(jìn)這個函式,在PHP噴error投降之前,做最後的嘗試:
// autoload.phpfunction __autoload($classname) { if ($classname === 'xxx.php'){ $filename = "./". $classname .".php"; include_once($filename); } else if ($classname === 'yyy.php'){ $filename = "./other_library/". $classname .".php"; include_once($filename); } else if ($classname === 'zzz.php'){ $filename = "./my_library/". $classname .".php"; include_once($filename); } // blah}
也因?yàn)镻HP這種「投降前最後一次嘗試」的行為,有時會讓沒注意到的人困惑「奇怪我的code怎麼跑得動?我根本沒有require啊..」,所以被稱為「magic method」。
如此一來,問題似乎解決了?
可惜還是有小缺點(diǎn)..,就是這個__autoload函式內(nèi)容會變得很巨大。以上面的例子來說,一下會去根目錄找、一下會去other_library資料夾、一下會去my_library資料夾尋找。在整理檔案的時候,顯得有些混亂。
spl_autoload_register
於是PHP從5.1.2開始,多提供了一個函式。
可以多寫幾個autoload函式,然後註冊起來,效果跟直接使用__autoload相同。
現(xiàn)在可以針對不同用途的類別,分批autoload了。
spl_autoload_register('my_library_loader');spl_autoload_register('other_library_loader');spl_autoload_register('basic_loader');function my_library_loader($classname) { $filename = "./my_library/". $classname .".php"; include_once($filename);}function other_library_loader($classname) { $filename = "./other_library/". $classname .".php"; include_once($filename);}function basic_loader($classname) { $filename = "./". $classname .".php"; include_once($filename);}
每個loader內(nèi)容可以做很多變化??梢远鄬懪袛嗍阶屗腔邸⒖梢赃M(jìn)行字串處理…。
自動載入類別的問題終於解決了…。
但是光上面的code也有15行,而且在每個project一定都會寫類似的東西。有沒有辦法自動產(chǎn)生這15行呢?
我的願望很簡單,我告訴你,反正我有my_library資料夾跟other_library資料夾,你自己進(jìn)去看到什麼類別就全部載入好不好…?
阿不對,全部載入剛又說效能不好,那你進(jìn)去看到什麼就全部想辦法用spl_autoload_register記起來好不好…?
我懶得打15行了,我只想打這幾個字:
$please_autoload = array( 'my_library', 'other_library');
可不可以發(fā)明一個工具,去吃$please_autoload這個變數(shù),然後自己想辦法載入一切啊…?
ㄟ等等,我連php程式碼都懶得打了,在web領(lǐng)域JSON格式更簡潔。允許我這樣打,好嗎?
{ "autoload": [ "my_library", "other_library" ]}
然後誰來個工具幫我產(chǎn)生一大串a(chǎn)utoload相關(guān)的php程式碼吧…,可以嗎?
可以。
Composer登場
首先,裝好composer(本文不介紹如何安裝。)
再來,建立一個composer.json檔,裡面輸入這些:
{ "autoload": { "classmap": [ "my_library", "other_library" ] }}
比原本希望的多打了一些字,不過差不多。
再來,在terminal輸入
composer install
執(zhí)行成功之後,你會看到一個vendor資料夾,內(nèi)含一個autoload.php。
沒錯,跟你夢想的一樣。你只要載入這個檔案:
require 'vendor/autoload.php';
你需要的所有類別,都會在適當(dāng)?shù)臅r候、以適當(dāng)?shù)姆绞阶詣虞d入。
php再也不會噴error說你「類別尚未定義」了!
這vendor資料夾裡面的一切,都只是php code而已,並沒有特別神奇的地方。只要去看autoload.php的原始碼,就能知道composer到底寫了哪些php code給你。
ㄟ等等,我寫的類別都放在my_library裡面了,other_library都是網(wǎng)路上copy下來的現(xiàn)成類別。我想要用Google API的Client類別、Doctrine資料庫管理抽象層類別、還有g(shù)uzzlehttp的發(fā)送request類別。
我連去下載這些檔案、然後丟進(jìn)這個資料夾都懶得做了,我根本不想手動建立other_library這個資料夾。composer真那麼神…不如連下載都幫我自動下載?可以嗎?
可以。
查詢一下那幾個套件在「然後’composer install’指令除了自動載入你的類別之外、還會自動下載你需要的類別、然後自動載入它們。
一樣require ‘vendor/autoload.php’就可以了。composer實(shí)在是太棒了
我的部落格
http://blog.turn.tw/?p=1039
http://blog.turn.tw/?p=1122