Illuminate/Foundation/Application.php


<?php namespace Illuminate\Foundation;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Container\Container;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\ServiceProvider;
use Illuminate\Events\EventServiceProvider;
use Illuminate\Routing\RoutingServiceProvider;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Illuminate\Contracts\Foundation\Application as ApplicationContract;

class Application extends Container implements ApplicationContract, HttpKernelInterface {

    /**
     * The Laravel framework version.
     *
     * @var string
     */
    const VERSION = '5.0.33';

    
/** * The base path for the Laravel installation. * 安装 Laravel 的基础路径(根目录)。 * * @var string */ protected $basePath;
/** * Indicates if the application has been bootstrapped before. * 指示应用程序在此前是否已经被引导。 * * @var bool */ protected $hasBeenBootstrapped = false;
/** * Indicates if the application has "booted". * 应用程序启动标记。 * * @var bool */ protected $booted = false;
/** * The array of booting callbacks. * 存储 booting 回调的数组。 * * @var array */ protected $bootingCallbacks = array();
/** * The array of booted callbacks. * 存储 booted 回调的数组。 * * @var array */ protected $bootedCallbacks = array();
/** * The array of terminating callbacks. * 存储 terminating 回调的数组。 * * @var array */ protected $terminatingCallbacks = array();
/** * All of the registered service providers. * 所有已注册的服务提供者。 * * @var array */ protected $serviceProviders = array();
/** * The names of the loaded service providers. * 所有已加载的服务提供者。 * * @var array */ protected $loadedProviders = array();
/** * The deferred services and their providers. * 需要延迟加载的服务和它的提供者。 * * @var array */ protected $deferredServices = array();
/** * The custom database path defined by the developer. * * @var string */ protected $databasePath;
/** * The custom storage path defined by the developer. * * @var string */ protected $storagePath;
/** * Indicates if the storage directory should be used for optimizations. * 标明 storage 目录是否可用于优化。 * * @var bool */ protected $useStoragePathForOptimizations = false;
/** * The environment file to load during bootstrapping. * 在引导时需要加载的环境文件。 * * @var string */ protected $environmentFile = '.env';
/** * Create a new Illuminate application instance. * 创建一个新的 Illuminate 应用程序实例。 * * @param string|null $basePath 应用程序基础路径(根目录) * @return void */ public function __construct($basePath = null) { // 注册基础绑定 $this->registerBaseBindings(); // 注册所有的基础服务提供者 // 事件 Illuminate\Events\EventServiceProvider@register // 路由 Illuminate\Routing\RoutingServiceProvider@register $this->registerBaseServiceProviders(); // 注册核心类别名 $this->registerCoreContainerAliases(); // 设置基础路径 if ($basePath) $this->setBasePath($basePath); }
/** * Get the version number of the application. * * @return string */ public function version() { return static::VERSION; }
/** * Register the basic bindings into the container. * 在容器中注册基础绑定 * * @return void */ protected function registerBaseBindings() { static::setInstance($this); // 将当前容器设置为共享实例 # $this->instance(抽象类, 实例) 在容器中注册共享实例 $this->instance('app', $this); $this->instance('Illuminate\Container\Container', $this); }
/** * Register all of the base service providers. * 注册所有的基础服务提供者 * * @return void */ protected function registerBaseServiceProviders() { // 统一调用服务提供者父类的 __construct() 方法创建服务提供者实例。 // 使用 $this->register(服务提供者实例) 方法进行注册。 // 事件 Illuminate\Events\EventServiceProvider@register // 注册 events 单例为 Illuminate\Events\Dispatcher 实例 // 且设置队列解析器为 Illuminate\Contracts\Queue\Queue $this->register(new EventServiceProvider($this)); // 路由 Illuminate\Routing\RoutingServiceProvider@register // Illuminate\Routing\Router 注册路由实例 // Illuminate\Routing\UrlGenerator 注册 Url 生成器实例 // Illuminate\Routing\Redirector 注册 Redirector(跳转)实例 // Illuminate\Routing\ResponseFactory 注册 Response(响应)实例 $this->register(new RoutingServiceProvider($this)); }
/** * Run the given array of bootstrap classes. * 运行给定数组中的引导类。 * * @param array $bootstrappers * @return void */ public function bootstrapWith(array $bootstrappers) { // 标记应用程序为“已引导” $this->hasBeenBootstrapped = true; foreach ($bootstrappers as $bootstrapper) { // 触发“bootstrapping: Xxx”事件 $this['events']->fire('bootstrapping: '.$bootstrapper, [$this]); // 实例化引导类,调用其 bootstrap 方法 $this->make($bootstrapper)->bootstrap($this); // 触发“bootstrapped: Xxx”事件 $this['events']->fire('bootstrapped: '.$bootstrapper, [$this]); } }
/** * Register a callback to run after loading the environment. * * @param \Closure $callback * @return void */ public function afterLoadingEnvironment(Closure $callback) { return $this->afterBootstrapping( 'Illuminate\Foundation\Bootstrap\DetectEnvironment', $callback ); }
/** * Register a callback to run before a bootstrapper. * * @param string $bootstrapper * @param Closure $callback * @return void */ public function beforeBootstrapping($bootstrapper, Closure $callback) { $this['events']->listen('bootstrapping: '.$bootstrapper, $callback); }
/** * Register a callback to run after a bootstrapper. * * @param string $bootstrapper * @param Closure $callback * @return void */ public function afterBootstrapping($bootstrapper, Closure $callback) { $this['events']->listen('bootstrapped: '.$bootstrapper, $callback); }
/** * Determine if the application has been bootstrapped before. * 判断应用程序在此前是否已经被引导。 * * @return bool */ public function hasBeenBootstrapped() { return $this->hasBeenBootstrapped; }
/** * Set the base path for the application. * 设置应用程序的基础路径。 * * @param string $basePath 基础路径 * @return $this */ public function setBasePath($basePath) { $this->basePath = $basePath; $this->bindPathsInContainer(); return $this; }
/** * Bind all of the application paths in the container. * 在容器中绑定所有应用程序路径。 * * @return void */ protected function bindPathsInContainer() { $this->instance('path', $this->path()); foreach (['base', 'config', 'database', 'lang', 'public', 'storage'] as $path) { $this->instance('path.'.$path, $this->{$path.'Path'}()); } }
/** * Get the path to the application "app" directory. * 获取应用程序的“app”目录的路径。 * * @return string */ public function path() { return $this->basePath.DIRECTORY_SEPARATOR.'app'; }
/** * Get the base path of the Laravel installation. * 获取安装 Laravel 的基础路径(根目录)。 * * @return string */ public function basePath() { return $this->basePath; }
/** * Get the path to the application configuration files. * 获取应用程序配置文件路径。 * * @return string */ public function configPath() { return $this->basePath.DIRECTORY_SEPARATOR.'config'; }
/** * Get the path to the database directory. * 获取到数据库文件目录的路径。 * * @return string */ public function databasePath() { return $this->databasePath ?: $this->basePath.DIRECTORY_SEPARATOR.'database'; }
/** * Set the database directory. * 设置数据库文件目录。 * * @param string $path * @return $this */ public function useDatabasePath($path) { $this->databasePath = $path; $this->instance('path.database', $path); return $this; }
/** * Get the path to the language files. * 获取语言文件路径。 * * @return string */ public function langPath() { return $this->basePath.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'lang'; }
/** * Get the path to the public / web directory. * 获取网站 public 目录的路径。 * * @return string */ public function publicPath() { return $this->basePath.DIRECTORY_SEPARATOR.'public'; }
/** * Get the path to the storage directory. * 获取缓存目录路径。 * * @return string */ public function storagePath() { return $this->storagePath ?: $this->basePath.DIRECTORY_SEPARATOR.'storage'; }
/** * Set the storage directory. * 设置缓存目录。 * * @param string $path * @return $this */ public function useStoragePath($path) { $this->storagePath = $path; $this->instance('path.storage', $path); return $this; }
/** * Set the environment file to be loaded during bootstrapping. * 设置引导时需要加载的环境文件。 * * @param string $file * @return $this */ public function loadEnvironmentFrom($file) { $this->environmentFile = $file; return $this; }
/** * Get the environment file the application is using. * 获取应用程序当前所使用的环境文件。 * * @return string */ public function environmentFile() { return $this->environmentFile ?: '.env'; }
/** * Get or check the current application environment. * 获取或检测当前应用程序的运行环境。 * * @param mixed * @return string */ public function environment() { if (func_num_args() > 0) { $patterns = is_array(func_get_arg(0)) ? func_get_arg(0) : func_get_args(); foreach ($patterns as $pattern) { if (str_is($pattern, $this['env'])) { return true; } } return false; } return $this['env']; }
/** * Determine if application is in local environment. * * @return bool */ public function isLocal() { return $this['env'] == 'local'; }
/** * Detect the application's current environment. * 检测应用程序的当前环境。 * * @param \Closure $callback * @return string */ public function detectEnvironment(Closure $callback) { $args = isset($_SERVER['argv']) ? $_SERVER['argv'] : null; return $this['env'] = (new EnvironmentDetector())->detect($callback, $args); }
/** * Determine if we are running in the console. * * @return bool */ public function runningInConsole() { return php_sapi_name() == 'cli'; }
/** * Determine if we are running unit tests. * * @return bool */ public function runningUnitTests() { return $this['env'] == 'testing'; }
/** * Register all of the configured providers. * 注册 providers 配置项中的所有服务提供者。 * * @return void */ public function registerConfiguredProviders() { $manifestPath = $this->getCachedServicesPath(); (new ProviderRepository($this, new Filesystem, $manifestPath)) ->load($this->config['app.providers']); }
/** * Register a service provider with the application. * 在应用程序中注册一个服务提供者 * * @param \Illuminate\Support\ServiceProvider|string $provider * @param array $options * @param bool $force * @return \Illuminate\Support\ServiceProvider */ public function register($provider, $options = array(), $force = false) { // 若存在,则获取已注册的服务提供者实例 if ($registered = $this->getProvider($provider) && ! $force) { return $registered; } // If the given "provider" is a string, we will resolve it, passing in the // application instance automatically for the developer. This is simply // a more convenient way of specifying your service provider classes. if (is_string($provider)) { // 解析类名,获得服务提供者实例 $provider = $this->resolveProviderClass($provider); } // 调用各服务提供者类的 register 方法 $provider->register(); // Once we have registered the service we will iterate through the options // and set each of them on the application so they will be available on // the actual loading of the service objects and for developer usage. foreach ($options as $key => $value) { $this[$key] = $value; } // 标记给定的服务提供者实例为“已注册”。 $this->markAsRegistered($provider); // If the application has already booted, we will call this boot method on // the provider class so it has an opportunity to do its boot logic and // will be ready for any usage by the developer's application logics. // 若应用程序已启动 if ($this->booted) { // 启动给定的服务提供者 // 调用各服务提供者类的 boot 方法 $this->bootProvider($provider); } return $provider; }
/** * Get the registered service provider instance if it exists. * 若存在,则获取已注册的服务提供者实例。 * * @param \Illuminate\Support\ServiceProvider|string $provider * @return \Illuminate\Support\ServiceProvider|null */ public function getProvider($provider) { $name = is_string($provider) ? $provider : get_class($provider); return array_first($this->serviceProviders, function($key, $value) use ($name) { return $value instanceof $name; }); }
/** * Resolve a service provider instance from the class name. * 解析一个类名,获得服务提供者实例。 * * @param string $provider * @return \Illuminate\Support\ServiceProvider */ public function resolveProviderClass($provider) { return new $provider($this); }
/** * Mark the given provider as registered. * 标记给定的服务提供者实例为“已注册”。 * * @param \Illuminate\Support\ServiceProvider * @return void */ protected function markAsRegistered($provider) { $this['events']->fire($class = get_class($provider), array($provider)); $this->serviceProviders[] = $provider; $this->loadedProviders[$class] = true; }
/** * Load and boot all of the remaining deferred providers. * * @return void */ public function loadDeferredProviders() { // We will simply spin through each of the deferred providers and register each // one and boot them if the application has booted. This should make each of // the remaining services available to this application for immediate use. foreach ($this->deferredServices as $service => $provider) { $this->loadDeferredProvider($service); } $this->deferredServices = array(); }
/** * Load the provider for a deferred service. * * @param string $service * @return void */ public function loadDeferredProvider($service) { if ( ! isset($this->deferredServices[$service])) { return; } $provider = $this->deferredServices[$service]; // If the service provider has not already been loaded and registered we can // register it with the application and remove the service from this list // of deferred services, since it will already be loaded on subsequent. if ( ! isset($this->loadedProviders[$provider])) { $this->registerDeferredProvider($provider, $service); } }
/** * Register a deferred provider and service. * * @param string $provider * @param string $service * @return void */ public function registerDeferredProvider($provider, $service = null) { // Once the provider that provides the deferred service has been registered we // will remove it from our local list of the deferred services with related // providers so that this container does not try to resolve it out again. if ($service) unset($this->deferredServices[$service]); $this->register($instance = new $provider($this)); if ( ! $this->booted) { $this->booting(function() use ($instance) { $this->bootProvider($instance); }); } }
/** * Resolve the given type from the container. * 从容器中解析给定类。 * * (Overriding Container::make) * * @param string $abstract 抽象类 * @param array $parameters 参数数组 * @return mixed */ public function make($abstract, $parameters = array()) { // 获取抽象的别名 $abstract = $this->getAlias($abstract); // 若需延迟加载 if (isset($this->deferredServices[$abstract])) { // 调用延迟加载方法 $this->loadDeferredProvider($abstract); } // 调用父类 make 方法 return parent::make($abstract, $parameters); }
/** * Determine if the given abstract type has been bound. * 判断给定类型是否已被绑定。 * * (Overriding Container::bound) * * @param string $abstract * @return bool */ public function bound($abstract) { // 判断是否为“延迟启动的服务”,或调用父类 bound 方法,判断该抽象类是否为已被绑定 return isset($this->deferredServices[$abstract]) || parent::bound($abstract); }
/** * Determine if the application has booted. * * @return bool */ public function isBooted() { return $this->booted; }
/** * Boot the application's service providers. * 启动应用程序的服务提供者。 * * @return void */ public function boot() { // 防止重复启动 if ($this->booted) return; // Once the application has booted we will also fire some "booted" callbacks // for any listeners that need to do work after this initial booting gets // finished. This is useful when ordering the boot-up processes we run. // 触发已绑定的 booting 回调 $this->fireAppCallbacks($this->bootingCallbacks); array_walk($this->serviceProviders, function($p) { // 循环调用各服务提供者的 bootProvider 方法 $this->bootProvider($p); }); // 标记为已启动 $this->booted = true; // 触发已绑定的 booted 回调 $this->fireAppCallbacks($this->bootedCallbacks); }
/** * Boot the given service provider. * 启动给定的服务提供者。 * * @param \Illuminate\Support\ServiceProvider $provider * @return void */ protected function bootProvider(ServiceProvider $provider) { // 若存在 boot 方法 if (method_exists($provider, 'boot')) { // 调用对应的 boot 方法 return $this->call([$provider, 'boot']); } }
/** * Register a new boot listener. * * @param mixed $callback * @return void */ public function booting($callback) { $this->bootingCallbacks[] = $callback; }
/** * Register a new "booted" listener. * * @param mixed $callback * @return void */ public function booted($callback) { $this->bootedCallbacks[] = $callback; if ($this->isBooted()) $this->fireAppCallbacks(array($callback)); }
/** * {@inheritdoc} */ public function handle(SymfonyRequest $request, $type = self::MASTER_REQUEST, $catch = true) { return $this['Illuminate\Contracts\Http\Kernel']->handle(Request::createFromBase($request)); }
/** * Determine if the application configuration is cached. * * @return bool */ public function configurationIsCached() { return $this['files']->exists($this->getCachedConfigPath()); }
/** * Get the path to the configuration cache file. * 获取配置文件的缓存路径。 * * @return string */ public function getCachedConfigPath() { if ($this->vendorIsWritableForOptimizations()) { return $this->basePath().'/vendor/config.php'; } else { return $this['path.storage'].'/framework/config.php'; } }
/** * Determine if the application routes are cached. * * @return bool */ public function routesAreCached() { return $this['files']->exists($this->getCachedRoutesPath()); }
/** * Get the path to the routes cache file. * * @return string */ public function getCachedRoutesPath() { if ($this->vendorIsWritableForOptimizations()) { return $this->basePath().'/vendor/routes.php'; } else { return $this['path.storage'].'/framework/routes.php'; } }
/** * Get the path to the cached "compiled.php" file. * * @return string */ public function getCachedCompilePath() { if ($this->vendorIsWritableForOptimizations()) { return $this->basePath().'/vendor/compiled.php'; } else { return $this->storagePath().'/framework/compiled.php'; } }
/** * Get the path to the cached services.json file. * * @return string */ public function getCachedServicesPath() { if ($this->vendorIsWritableForOptimizations()) { return $this->basePath().'/vendor/services.json'; } else { return $this->storagePath().'/framework/services.json'; } }
/** * Determine if vendor path is writable. * 判断 vendor 目录是否可写。 * * @return bool */ public function vendorIsWritableForOptimizations() { if ($this->useStoragePathForOptimizations) return false; return is_writable($this->basePath().'/vendor'); }
/** * Determines if storage directory should be used for optimizations. * 确定是否为优化使用 storage 目录。 * * @param bool $value * @return $this */ public function useStoragePathForOptimizations($value = true) { $this->useStoragePathForOptimizations = $value; return $this; }
/** * Call the booting callbacks for the application. * 触发应用程序的 booting 回调。 * * @param array $callbacks * @return void */ protected function fireAppCallbacks(array $callbacks) { foreach ($callbacks as $callback) { call_user_func($callback, $this); } }
/** * Determine if the application is currently down for maintenance. * * @return bool */ public function isDownForMaintenance() { return file_exists($this->storagePath().DIRECTORY_SEPARATOR.'framework'.DIRECTORY_SEPARATOR.'down'); }
/** * Register a maintenance mode event listener. * * @param \Closure $callback * @return void */ public function down(Closure $callback) { $this['events']->listen('illuminate.app.down', $callback); }
/** * Throw an HttpException with the given data. * * @param int $code * @param string $message * @param array $headers * @return void * * @throws \Symfony\Component\HttpKernel\Exception\HttpException */ public function abort($code, $message = '', array $headers = array()) { if ($code == 404) { throw new NotFoundHttpException($message); } throw new HttpException($code, $message, null, $headers); }
/** * Register a terminating callback with the application. * * @param \Closure $callback * @return $this */ public function terminating(Closure $callback) { $this->terminatingCallbacks[] = $callback; return $this; }
/** * Terminate the application. * * @return void */ public function terminate() { foreach ($this->terminatingCallbacks as $terminating) { $this->call($terminating); } }
/** * Get the service providers that have been loaded. * * @return array */ public function getLoadedProviders() { return $this->loadedProviders; }
/** * Get the application's deferred services. * * @return array */ public function getDeferredServices() { return $this->deferredServices; }
/** * Set the application's deferred services. * * @param array $services * @return void */ public function setDeferredServices(array $services) { $this->deferredServices = $services; }
/** * Add an array of services to the application's deferred services. * * @param array $services * @return void */ public function addDeferredServices(array $services) { $this->deferredServices = array_merge($this->deferredServices, $services); }
/** * Determine if the given service is a deferred service. * * @param string $service * @return bool */ public function isDeferredService($service) { return isset($this->deferredServices[$service]); }
/** * Get the current application locale. * * @return string */ public function getLocale() { return $this['config']->get('app.locale'); }
/** * Set the current application locale. * * @param string $locale * @return void */ public function setLocale($locale) { $this['config']->set('app.locale', $locale); $this['translator']->setLocale($locale); $this['events']->fire('locale.changed', array($locale)); }
/** * Register the core class aliases in the container. * 在容器中注册核心类别名 * * @return void */ public function registerCoreContainerAliases() { $aliases = array( 'app' => ['Illuminate\Foundation\Application', 'Illuminate\Contracts\Container\Container', 'Illuminate\Contracts\Foundation\Application'], 'artisan' => ['Illuminate\Console\Application', 'Illuminate\Contracts\Console\Application'], 'auth' => 'Illuminate\Auth\AuthManager', 'auth.driver' => ['Illuminate\Auth\Guard', 'Illuminate\Contracts\Auth\Guard'], 'auth.password.tokens' => 'Illuminate\Auth\Passwords\TokenRepositoryInterface', 'blade.compiler' => 'Illuminate\View\Compilers\BladeCompiler', 'cache' => ['Illuminate\Cache\CacheManager', 'Illuminate\Contracts\Cache\Factory'], 'cache.store' => ['Illuminate\Cache\Repository', 'Illuminate\Contracts\Cache\Repository'], 'config' => ['Illuminate\Config\Repository', 'Illuminate\Contracts\Config\Repository'], 'cookie' => ['Illuminate\Cookie\CookieJar', 'Illuminate\Contracts\Cookie\Factory', 'Illuminate\Contracts\Cookie\QueueingFactory'], 'encrypter' => ['Illuminate\Encryption\Encrypter', 'Illuminate\Contracts\Encryption\Encrypter'], 'db' => 'Illuminate\Database\DatabaseManager', 'events' => ['Illuminate\Events\Dispatcher', 'Illuminate\Contracts\Events\Dispatcher'], 'files' => 'Illuminate\Filesystem\Filesystem', 'filesystem' => ['Illuminate\Filesystem\FilesystemManager', 'Illuminate\Contracts\Filesystem\Factory'], 'filesystem.disk' => 'Illuminate\Contracts\Filesystem\Filesystem', 'filesystem.cloud' => 'Illuminate\Contracts\Filesystem\Cloud', 'hash' => 'Illuminate\Contracts\Hashing\Hasher', 'translator' => ['Illuminate\Translation\Translator', 'Symfony\Component\Translation\TranslatorInterface'], 'log' => ['Illuminate\Log\Writer', 'Illuminate\Contracts\Logging\Log', 'Psr\Log\LoggerInterface'], 'mailer' => ['Illuminate\Mail\Mailer', 'Illuminate\Contracts\Mail\Mailer', 'Illuminate\Contracts\Mail\MailQueue'], 'paginator' => 'Illuminate\Pagination\Factory', 'auth.password' => ['Illuminate\Auth\Passwords\PasswordBroker', 'Illuminate\Contracts\Auth\PasswordBroker'], 'queue' => ['Illuminate\Queue\QueueManager', 'Illuminate\Contracts\Queue\Factory', 'Illuminate\Contracts\Queue\Monitor'], 'queue.connection' => 'Illuminate\Contracts\Queue\Queue', 'redirect' => 'Illuminate\Routing\Redirector', 'redis' => ['Illuminate\Redis\Database', 'Illuminate\Contracts\Redis\Database'], 'request' => 'Illuminate\Http\Request', 'router' => ['Illuminate\Routing\Router', 'Illuminate\Contracts\Routing\Registrar'], 'session' => 'Illuminate\Session\SessionManager', 'session.store' => ['Illuminate\Session\Store', 'Symfony\Component\HttpFoundation\Session\SessionInterface'], 'url' => ['Illuminate\Routing\UrlGenerator', 'Illuminate\Contracts\Routing\UrlGenerator'], 'validator' => ['Illuminate\Validation\Factory', 'Illuminate\Contracts\Validation\Factory'], 'view' => ['Illuminate\View\Factory', 'Illuminate\Contracts\View\Factory'], ); foreach ($aliases as $key => $aliases) { foreach ((array) $aliases as $alias) { // 在容器的别名数组中存储指定抽象类的别名。 $this->alias($key, $alias); } } }
/** * Flush the container of all bindings and resolved instances. * * @return void */ public function flush() { parent::flush(); $this->loadedProviders = []; } }