composer概述
一開始,最吸引我的當屬Composer了,因為之前從沒用過Composer。
Composer 是php中用來管理依賴關系的工具,你只需在自己的項目中聲明所依賴的外部工具庫,Composer就會幫你安裝這些依賴的庫文件。運行Composer 需要 PHP 5.3.2+ 以上版本。
使用composer
第一步,聲明依賴關系。比方說,你正在創建的一個項目需要一個庫來做日志記錄。你決定使用monolog。為了將它添加到你的項目中,你所需要做的就是創建一個composer.json
文件,其中描述了項目的依賴關系。
{ "require": { "monolog/monolog": "1.2.*" }}
第二步,使用composer。在項目根目錄,執行安裝命令,執行完畢后,monolog就會被下載到vendor/monolog/monolog
目錄。
$ php composer.phar install
第三步,類的自動加載。除了庫的下載,Composer 還準備了一個自動加載文件,它可以加載 Composer 下載的庫中所有的類文件。使用它,你只需要將下面這行代碼添加到你項目的引導文件中:
require 'vendor/autoload.php';
這使得你可以很容易的使用第三方代碼。例如:如果你的項目依賴 monolog,你就可以像這樣開始使用這個類庫,并且他們將被自動加載。
$log = new Monolog/Logger('name');$log->pushHandler(new Monolog/Handler/StreamHandler('app.log', Monolog/Logger::WARNING));$log->addWarning('Foo');
Composer自動加載探秘
在現實世界中使用工具時,如果理解了工具的工作原理,使用起來就會更加有底氣。對于一個第一次接觸laravel,且是第一次接觸 composer 的新手來說,如果理解Composer 是如何工作的,使用起來將會更加自如。
我的理解是,composer 根據聲明的依賴關系,從相關庫的 源 下載代碼文件,并根據依賴關系在Composer目錄下生成供類自動加載的 PHP 腳本,使用的時候,項目開始處引入 “/vendor/autoload.php” 文件,就可以直接實例化這些第三方類庫中的類了。那么,Composer 是如何實現類的自動加載的呢?接下來,我們從laravel 的入口文件開始順藤摸瓜往里跟進,來一睹 Composer 自動加載的奧妙。
1.代碼清單laravel/public/index.php
#laravel/public/index.phPRequire __DIR__.'/../bootstrap/autoload.php';$app = require_once __DIR__.'/../bootstrap/start.php';$app->run();
第一行先是引入了laravel/bootstrap/autoload.php,不做解釋,打開該文件。
2.代碼清單laravel/bootstrap/autoload.php
define('LARAVEL_START', microtime(true));require __DIR__.'/../vendor/autoload.php';if (file_exists($compiled = __DIR__.'/compiled.php')){ require $compiled;}Patchwork/Utf8/Bootup::initMbstring();
第一行定義了程序開始執行的時間點。緊接著第二行,引入了 laravel/vendor/autoload.php。
第七行,前面說過,引入Composer的autoload.php之后就可以直接使用第三方類庫中的類了,這里就是直接使用的Bootup 類。下面來看看/vendor/autoload.php 到底做了什么。
3.代碼清單laravel/vendor/autoload.php
1 // autoload.php @generated by Composer2 3 require_once __DIR__ . '/composer' . '/autoload_real.php';4 5 return ComposerAutoloaderInit9b2a1b1cf01c9a870ab98748dc5f1256::getLoader();
到這里,馬上就進入自動加在的大門了。
這個文件很簡單,第5行的函數名是不是看的一頭霧水?別被嚇到了,他就是個類名而已。這個類是在第3行引入的文件laravel/vendor/composer/autoload_real.php 里頭聲明的,接下來打開該文件看getLoader();
4.代碼清單laravel/vendor/composer/autoload_real.php
1 <?php 2 3 // autoload_real.php @generated by Composer 4 5 class ComposerAutoloaderInit9b2a1b1cf01c9a870ab98748dc5f1256 6 { 7 private static $loader; 8 9 public static function loadClassLoader($class)10 {11 if ('Composer/Autoload/ClassLoader' === $class) {12 require __DIR__ . '/ClassLoader.php';13 }14 }15 16 17 public static function getLoader()18 {19 if (null !== self::$loader) {20 return self::$loader;21 }22 23 spl_autoload_register(array('ComposerAutoloaderInit9b2a1b1cf01c9a870ab98748dc5f1256', 'loadClassLoader'), true, true);24 self::$loader = $loader = new /Composer/Autoload/ClassLoader();25 spl_autoload_unregister(array('ComposerAutoloaderInit9b2a1b1cf01c9a870ab98748dc5f1256', 'loadClassLoader'));26 27 $vendorDir = dirname(__DIR__); 28 $baseDir = dirname($vendorDir);29 30 $includePaths = require __DIR__ . '/include_paths.php'; 31 32 array_push($includePaths, get_include_path());33 set_include_path(join(PATH_SEPARATOR, $includePaths));34 35 36 $map = require __DIR__ . '/autoload_namespaces.php';37 foreach ($map as $namespace => $path) {38 $loader->set($namespace, $path);39 }40 41 $map = require __DIR__ . '/autoload_psr4.php';42 foreach ($map as $namespace => $path) {43 $loader->setPsr4($namespace, $path);44 }45 46 $classMap = require __DIR__ . '/autoload_classmap.php';47 if ($classMap) {48 $loader->addClassMap($classMap);49 }50 51 52 $loader->register(true);53 54 $includeFiles = require __DIR__ . '/autoload_files.php';55 foreach ($includeFiles as $file) {56 composerRequire9b2a1b1cf01c9a870ab98748dc5f1256($file);57 }58 59 return $loader;60 }61 }62 63 function composerRequire9b2a1b1cf01c9a870ab98748dc5f1256($file)及$loader->addClassMap()64 {65 require $file;66 }
第17行,getLoader()中先是判斷當前類中的 $loader 值,如果不是 null 就返回,這個可以略過。接著實例化了ClassLoader 類給 $loader ,laravel/vendor/composer/ClassLoader.php
這里引入了幾個文件,這些文件是由composer自動生成的,當依賴關系發生改變時不需要修改這些腳本,運行composer重新生成即可。
laravel/vendor/composer/autoloade_namespace.php
laravel/vendor/composer/autoloade_prs4.php
laravel/vendor/composer/autoloade_classmap.php
laravel/vendor/composer/autoloade_files.php
在設置完一堆的 path 信息后,執行了$loader->set()和$loader->setPsr4()及$loader->addClassMap(),然后 進行了$loader->register(true);現在我們一個個來看。
5.代碼清單laravel/vendor/composer/ClassLoader.php
1 <?php 2 3 /* 4 * This file is part of Composer. 5 * 6 * (c) Nils Adermann <naderman@naderman.de> 7 * Jordi Boggiano <j.boggiano@seld.be> 8 * 9 * For the full copyright and license information, please view the LICENSE 10 * file that was distributed with this source code. 11 */ 12 13 namespace Composer/Autoload; 14 15 /** 16 * ClassLoader implements a PSR-0 class loader 17 * 18 * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md 19 * 20 * $loader = new /Composer/Autoload/ClassLoader(); 21 * 22 * // register classes with namespaces 23 * $loader->add('Symfony/Component', __DIR__.'/component'); 24 * $loader->add('Symfony', __DIR__.'/framework'); 25 * 26 * // activate the autoloader 27 * $loader->register(); 28 * 29 * // to enable searching the include path (eg. for PEAR packages) 30 * $loader->setUseIncludePath(true); 31 * 32 * In this example, if you try to use a class in the Symfony/Component 33 * namespace or one of its children (Symfony/Component/Console for instance), 34 * the autoloader will first look for the class under the component/ 35 * directory, and it will then fallback to the framework/ directory if not 36 * found before giving up. 37 * 38 * This class is loosely based on the Symfony UniversalClassLoader. 39 * 40 * @author Fabien Potencier <fabien@symfony.com> 41 * @author Jordi Boggiano <j.boggiano@seld.be> 42 */ 43 class ClassLoader 44 { 45 // PSR-4 46 private $prefixLengthsPsr4 = array(); 47 private $prefixDirsPsr4 = array(); 48 private $fallbackDirsPsr4 = array(); 49 50 // PSR-0 51 private $prefixesPsr0 = array(); 52 private $fallbackDirsPsr0 = array(); 53 54 private $useIncludePath = false; 55 private $classMap = array(); 56 57 public function getPrefixes() 58 { 59 return call_user_func_array('array_merge', $this->prefixesPsr0); 60 } 61 62 public function getPrefixesPsr4() 63 { 64 return $this->prefixDirsPsr4; 65 } 66 67 public function getFallbackDirs() 68 { 69 return $this->fallbackDirsPsr0; 70 } 71 72 public function getFallbackDirsPsr4() 73 { 74 return $this->fallbackDirsPsr4; 75 } 76 77 public function getClassMap() 78 { 79 return $this->classMap; 80 } 81 82 /** 83 * @param array $classMap
新聞熱點
疑難解答