美工统筹SEO,为企业电子商务营销助力!
PHP办理依靠(dependency)干系东西 Composer的主动加载(autoload)
一佰互联网站建造(www.taishanly.com) 宣布日期 2020-04-29 09:01:07 阅读数: 183
举例来讲,假定咱们的名目想要操纵 monolog 这个日记东西,就须要在composer.json里告知composer咱们须要它:
{ "require": { "monolog/monolog": "1.*" } }
以后履行:
php composer.phar install
好,此刻装置完了,该怎样操纵呢?Composer主动天生了一个autoload文件,你只须要援用它
require "/path/to/vendor/autoload.php";
而后就能够很是便利的去操纵第三方的类库了,是不是是感受很棒啊!对咱们须要的monolog,就能够如许用了:
use MonologLogger; use MonologHandlerStreamHandler; // create a log channel $log = new Logger("name"); $log->pushHandler(new StreamHandler("/path/to/log/log_name.log", Logger::WARNING)); // add records to the log $log->addWarning("Foo"); $log->addError("Bar");
在这个进程中,Composer做了甚么呢?它天生了一个autoloader,再根据各个包本身的autoload设置装备摆设,从而帮咱们停止主动加载的使命。(若是对autoload这局部内容不太领会,能够看我之前的 一篇文章
)接上去让咱们看看Composer是怎样做的吧。
对第三方包的主动加载,Composer供给了四种体例的撑持,别离是 PSR-0和PSR-4的主动加载(我的一篇文章也有先容过它们),天生class-map,和间接包罗files的体例。
PSR-4是composer保举操纵的一种体例,由于它更容易操纵并能带来更简练的目次布局。在composer.json里是如许停止设置装备摆设的:
{ "autoload": { "psr-4": { "Foo": "src/", } } }
key和value就界说出了namespace和到呼应path的映照。根据PSR-4的法则,当试图主动加载 "FooBarBaz" 这个class时,会去寻觅 "src/Bar/Baz.php" 这个文件,若是它存在则停止加载。注重, "Foo"
并不出此刻文件途径中,这是与PSR-0差别的一点,若是PSR-0有此设置装备摆设,那末会去寻觅
"src/Foo/Bar/Baz.php"
这个文件。
别的注重PSR-4和PSR-0的设置装备摆设里,"Foo"开头的定名空间分开符必须加上并且停止本义,以防呈现"Foo"婚配到了"FooBar"如许的不测产生。
在composer装置或更新完以后,psr-4的设置装备摆设换被转换成namespace为key,dir path为value的Map的情势,并写入天生的 vendor/composer/autoload_psr4.php 文件当中。
{ "autoload": { "psr-0": { "Foo": "src/", } } }
终究这个设置装备摆设也以Map的情势写入天生的
vendor/composer/autoload_namespaces.php
文件当中。
Class-map体例,则是经由过程设置装备摆设指定的目次或文件,而后在Composer装置或更新时,它会扫描指定目次下以.php或.inc开头的文件中的class,天生class到指定file path的映照,并插手新天生的 vendor/composer/autoload_classmap.php 文件中,。
{ "autoload": { "classmap": ["src/", "lib/", "Something.php"] } }
比方src/下有一个BaseController类,那末在autoload_classmap.php文件中,就会天生如许的设置装备摆设:
"BaseController" => $baseDir . "/src/BaseController.php"
Files体例,便是手动指定供间接加载的文件。比方说咱们有一系列全局的helper functions,能够放到一个helper文件里而后间接停止加载
{ "autoload": { "files": ["src/MyLibrary/functions.php"] } }
它会天生一个array,包罗这些设置装备摆设中指定的files,再写入新天生的
vendor/composer/autoload_files.php
文件中,以供autoloader间接停止加载。
下面来看看composer autoload的代码吧
<?php // autoload_real.php @generated by Composer class ComposerAutoloaderInit73612b48e6c3d0de8d56e03dece61d11 { private static $loader; public static function loadClassLoader($class) { if ("ComposerAutoloadClassLoader" === $class) { require __DIR__ . "/ClassLoader.php"; } } public static function getLoader() { if (null !== self::$loader) { return self::$loader; } spl_autoload_register(array("ComposerAutoloaderInit73612b48e6c3d0de8d56e03dece61d11", "loadClassLoader"), true, true); self::$loader = $loader = new ComposerAutoloadClassLoader(); spl_autoload_unregister(array("ComposerAutoloaderInit73612b48e6c3d0de8d56e03dece61d11", "loadClassLoader")); $vendorDir = dirname(__DIR__); //verdor第三方类库供给者目次 $baseDir = dirname($vendorDir); //全部操纵的目次 $includePaths = require __DIR__ . "/include_paths.php"; array_push($includePaths, get_include_path()); set_include_path(join(PATH_SEPARATOR, $includePaths)); $map = require __DIR__ . "/autoload_namespaces.php"; foreach ($map as $namespace => $path) { $loader->set($namespace, $path); } $map = require __DIR__ . "/autoload_psr4.php"; foreach ($map as $namespace => $path) { $loader->setPsr4($namespace, $path); } $classMap = require __DIR__ . "/autoload_classmap.php"; if ($classMap) { $loader->addClassMap($classMap); } $loader->register(true); $includeFiles = require __DIR__ . "/autoload_files.php"; foreach ($includeFiles as $file) { composerRequire73612b48e6c3d0de8d56e03dece61d11($file); } return $loader; } } function composerRequire73612b48e6c3d0de8d56e03dece61d11($file) { require $file; }
起首初始化ClassLoader类,而后顺次用下面提到的4种加载体例来注册/间接加载,ClassLoader的一些焦点代码以下:
/** * @param array $classMap Class to filename map */ public function addClassMap(array $classMap) { if ($this->classMap) { $this->classMap = array_merge($this->classMap, $classMap); } else { $this->classMap = $classMap; } } /** * Registers a set of PSR-0 directories for a given prefix, * replacing any others previously set for this prefix. * * @param string $prefix The prefix * @param array|string $paths The PSR-0 base directories */ public function set($prefix, $paths) { if (!$prefix) { $this->fallbackDirsPsr0 = (array) $paths; } else { $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; } } /** * Registers a set of PSR-4 directories for a given namespace, * replacing any others previously set for this namespace. * * @param string $prefix The prefix/namespace, with trailing "" * @param array|string $paths The PSR-4 base directories * * @throws InvalidArgumentException */ public function setPsr4($prefix, $paths) { if (!$prefix) { $this->fallbackDirsPsr4 = (array) $paths; } else { $length = strlen($prefix); if ("" !== $prefix[$length - 1]) { throw new InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); } $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; $this->prefixDirsPsr4[$prefix] = (array) $paths; } } /** * Registers this instance as an autoloader. * * @param bool $prepend Whether to prepend the autoloader or not */ public function register($prepend = false) { spl_autoload_register(array($this, "loadClass"), true, $prepend); } /** * Loads the given class or interface. * * @param string $class The name of the class * @return bool|null True if loaded, null otherwise */ public function loadClass($class) { if ($file = $this->findFile($class)) { includeFile($file); return true; } } /** * Finds the path to the file where the class is defined. * * @param string $class The name of the class * * @return string|false The path if found, false otherwise */ public function findFile($class) { //这是PHP5.3.0 - 5.3.2的一个bug 详见http://bugs.php.net/50731 if ("" == $class[0]) { $class = substr($class, 1); } // class map 体例的查找 if (isset($this->classMap[$class])) { return $this->classMap[$class]; } //psr-0/4体例的查找 $file = $this->findFileWithExtension($class, ".php"); // Search for Hack files if we are running on HHVM if ($file === null && defined("HHVM_VERSION")) { $file = $this->findFileWithExtension($class, ".hh"); } if ($file === null) { // Remember that this class does not exist. return $this->classMap[$class] = false; } return $file; } private function findFileWithExtension($class, $ext) { // PSR-4 lookup $logicalPathPsr4 = strtr($class, "", DIRECTORY_SEPARATOR) . $ext; $first = $class[0]; if (isset($this->prefixLengthsPsr4[$first])) { foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) { if (0 === strpos($class, $prefix)) { foreach ($this->prefixDirsPsr4[$prefix] as $dir) { if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) { return $file; } } } } } // PSR-4 fallback dirs foreach ($this->fallbackDirsPsr4 as $dir) { if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { return $file; } } // PSR-0 lookup if (false !== $pos = strrpos($class, "")) { // namespaced class name $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) . strtr(substr($logicalPathPsr4, $pos + 1), "_", DIRECTORY_SEPARATOR); } else { // PEAR-like class name $logicalPathPsr0 = strtr($class, "_", DIRECTORY_SEPARATOR) . $ext; } if (isset($this->prefixesPsr0[$first])) { foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { if (0 === strpos($class, $prefix)) { foreach ($dirs as $dir) { if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { return $file; } } } } } // PSR-0 fallback dirs foreach ($this->fallbackDirsPsr0 as $dir) { if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { return $file; } } // PSR-0 include paths. if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { return $file; } } /** * Scope isolated include. * * Prevents access to $this/self from included files. */ function includeFile($file) { include $file; }