Laravel 学习笔记之 Composer 自动加载

说明:本文主要以Laravel的容器类Container为例做简单说明Composer的自动加载机制。

Composer的自动加载机制

1、初始化一个composer项目

在一个空目录下composer安装Laravel的容器Container包:

composer require illuminate/container

然后在该目录下新建一个index.php文件,然后分析下Container类为何能被实例化:

<?php
/**
 * Created by PhpStorm.
 * User: liuxiang
 * Date: 16/5/12
 * Time: 19:59
 */
require_once __DIR__.‘/vendor/autoload.php‘;

$container = new Illuminate\Container\Container();
var_dump($container);

2、分析下composer加载类的流程

使用composer最大的好处是只需最开始require一个autoload.php文件,就可以new你所需要的类了,不再需要传统的方式A文件内各种include跳到B文件又各种include,非常头疼。

Composer按照四种规范来加载文件:

  • psr-4
  • psr-0(这种规范某些部分不是很优雅)
  • classmap(命名空间和文件路径的映射)
  • files

ComposerAutoloaderInit88609474169d8656473fa0223c682a7a这个类是composer为了防止类冲突搞了一个命名ComposerAutoloaderInit+hash,不管咋样,require_once这个类后需要返回的是一个加载器$loader,而这个加载器经过四种规范遍历后,由null被填充为含有各种变量值的ClassLoader对象。

如果仔细观察autoload_classmap.php、autoload_namespaces.php、autoload_psr4.php和autoload_files(这里用了Container包是没有这个文件的,但Laravel整个项目是有的)文件后,这些都按照对应的规范返回要么命名空间与路径的映射,要么完整路径与某个哈希的映射。

从上图中能看出这个composer初始化路径的流程,重点是ClassLoader这个类的loadClass($class)这个方法,是通过spl_autoload_register这个PHP自动加载函数来注册到autoload函数栈中,最后返回一个$loader加载器,而这个加载器是包含一些私有变量的,由于本Container包只包含Illuminate\Container和Illuminate\Contracts,且都是psr-4规范,则私有变量$prefixLengthsPsr4和$prefixDirsPsr4就包含了命名空间路径映射的数组值,其余私有变量就是空。

最后返回一个加载器$loader,然后需要实例化一个类时,就会根据loadClass($class)来寻找对应的文件,看下文。

Container类的实例化过程#

$loader这个加载器已经有了,而且它还是塞满了各种私有变量,这些变量值为命名空间路径映射或者路径哈希映射等,当然这里只有命名空间路径映射这种psr-4规范了。也就是说,一句require_once这个autoload.php文件后就拿到了一个饱满的$loader,然后现在开始new一个类Container,那如何找到这个Container.php文件路径的呢?

从第二个序列图就可看出,首先调用ClassLoader中的loadClass()这个函数来找文件路径,传入的$class变量值是“Illuminate\Container\Container”这个字符串,然后又继续调用findFile($class)函数先做classmap查找,然后进入findFileWithExtension($class,‘.php‘)中做psr-4/psr-0查找,其实就是搜寻这些私有变量值,比如这里Container类是psr-4规范,那就去$prefixLengthsPsr4/$prefixDirsPsr4这些psr-4私有变量中查找文件绝对路径,返回一个$file,再include下就等于这个类可以被实例化了。当然,这里Container.php文件绝对路径被找到后,发现它还实现了一个接口ContractContainer,那就再去同样方式找这个文件:psr-4根据命名空间Illuminate\Contracts\Container\Container去找这个接口对应的绝对路径。

总之,当实例化一个类时,这个$loader就去根据四种规范找该文件的绝对路径,如果这个类还有继承或实现关系,那就递归找。

自定义一个类文件#

现在自己写一个类文件,当实例化的时候,然后让composer来自动加载,怎么做?

修改composer.json文件:

{
    "require": {
        "illuminate/container": "^5.2"
    },
    "autoload": {
        "psr-4": {
            "App\\": "app/"
        }
    }
}

这里按照psr-4规范来,然后在项目根目录下使用命令:

composer install

发现autoload_psr4.php文件会多一个数组值:

return array(
    ‘Illuminate\\Contracts\\‘ => array($vendorDir . ‘/illuminate/contracts‘),
    ‘Illuminate\\Container\\‘ => array($vendorDir . ‘/illuminate/container‘),
    ‘App\\‘ => array($baseDir . ‘/app‘),
);

然后在项目根目录下新建文件:

// app/Test/Test.php文件
<?php
/**
 * Created by PhpStorm.
 * User: liuxiang
 * Date: 16/5/12
 * Time: 21:52
 */

namespace App\Test;

class Test
{
    public function index()
    {
        echo "This is a custom class which will be autoload by composer\n";
    }
}

在index.php文件中就可以实例化Test类并调用其对象函数了:

require_once __DIR__.‘/vendor/autoload.php‘;

//$container = new Illuminate\Container\Container();
//var_dump($container);

$test = new App\Test\Test();
$test->index();

终端执行输出:

通过在Composer中注册下,Composer就可以帮我们找到类文件,就不需要自己各种include,只需开始一句require_once就行,真的很方便。

One More Thing...

配置Xdebug。强烈推荐在自己的IDE中配置Xdebug,作者使用PHPStorm,并配置了Xdebug,这会提高阅读源码的效率。具体操作流程可以谷歌文档,应该很多,Netbeans或者ZendStudio应该也有很多配置文档。如果有配置不成功的,可以在本文留言下问题,作者会尽量解答。

PlantUML插件的安装。本文UML序列图用的是PlantUML这个插件来做的,还比较好用,推荐下。可以在PHPStorm插件库里搜UML就行,然后新建一个文件时会发现多了好几个UML选项,并且还有一个PlantUML窗口:

关于这个PlantUML有一篇文章还挺好:Create Beautiful UML Diagrams in Minutes from the JetBrains IDE,还有它的官网(就是有各种广告):PlantUML

总结:本文主要聊了下Composer的加载流程,并以Laravel的Illuminate\Container包为例具体说明实例化类时是如何找到其文件的,并讲述如何自定义自己的类并通过Composer来注册和加载。过两天还想结合PHP的字符串和数组这些基础知识新开篇章,到时见。

时间: 2024-08-10 11:30:42

Laravel 学习笔记之 Composer 自动加载的相关文章

composer自动加载一个文件后必须执行命令composer dump-autoload

"autoload": { "classmap": [ "database" ], "psr-4": { "App\\": "app/" }, "files":[ "app/Common/function.php", "api/qqOauth/qqConnectAPI.php" ] }, 比如我新增了一个qq的登录api(api

Quartz.net 2.x 学习笔记03-使用反射加载定时任务

将定时任务信息存储在XML文件中,使用反射加载定时任务 首先新建一个MVC的空站点,使用NuGet添加对Quartz.net和Common.Logging.Log4Net1213的引用,同时使用NuGet管理器控制台执行命令更新log4net,PM> update-package log4net 接着在解决方案中添加一个类库Library项目 类库项目也添加对Quartz.net的引用 下面可以编写代码了,在Library类库中添加一个JobBase类,3个Job类,和一个Job管理类(假设分别

Openstack学习笔记之——Neutron-server服务加载与启动源码分析(三)

本文是在学习Openstack的过程中整理和总结,由于时间和个人能力有限,错误之处在所难免,欢迎指正! 在Neutron-server服务加载与启动源码分析(二)中搞定模块功能的扩展和加载,我们就回到Neutron-server服务加载与启动源码分析(一)中的_run_wsgi函数 <span style="font-size:14px;">def _run_wsgi(app_name): app = config.load_paste_app(app_name) ifno

(Object-C)学习笔记 --OC的懒加载和单例方法

OC的懒加载 什么是懒加载: 懒加载——也称为延迟加载,即在需要的时候才加载(效率低,占用内存小).所谓懒加载,写的是其get方法. 注意:如果是懒加载的话则一定要注意先判断是否已经有了,如果没有那么再去进行实例化. 懒加载的好处 (1)不必将创建对象的代码全部写在viewDidLoad方法中,代码的可读性更强 (2)每个控件的getter方法中分别负责各自的实例化处理,代码彼此之间的独立性强,松耦合 懒加载的例子: #import "MusicTableViewController.h&quo

4月6日学习笔记——如何提高网页加载速度(前端面试考点)

网页的加载速度是评估网站质量一个重要指标.原因在于大多数用户能够容忍的网页加载时间只有几秒,如果超出了访客的忍受范围他们会毫不留情地关掉你的网 页,所以网页载入速度会极大地影响网站的流量和访问.以下总结了几种可以明显提高网站加载速度的初步简单技巧方式,如果你的网站存在载入速度慢的问题不妨 与此为参考对网页做些初步优化. 网页加载提速之 – 优化网页图片文件 你的网页一定有图片,加载一个网页往往图片的总尺寸是最大的,特别是那些颜色丰富的背景图片和大副广告图片.所以一般要在同等图片质量的情况下要尽可

Unity学习笔记13——代码动态加载Prefab预设体

在进行一些功能开发的时候,我们常常将一些能够复用的对象制作成.prefab的预设物体,然后将预设体存放到Resources目录之下,使用时再动态加载到场景中并进行实例化.例如:子弹.特效甚至音频等,都能制作成预设体. 一.预设动态加载到场景: 一个预设体要能够通过代码控制在场景中进行显示,需要三个步骤,这里我们以动态加载怪物血条为例子分析一个常见的误区: 1.预设体资源加载: //加载预设体资源 GameObject hp_bar = (GameObject)Resources.Load("Pr

vue.js学习笔记(二):如何加载本地json文件

在项目开发的过程中,因为无法和后台的数据做交互,所以我们可以自建一个假数据文件(如data.json)到项目文件夹中,这样我们就可以模仿后台的数据进行开发.但是,如何在一个vue.js 项目中引入本地的json文件呢,下面就将步骤贴出来.(此时项目是由webpack打包而成). 整个项目是由webpack打包而成,具体步骤上网查找.具体项目结构如下: 1:我们找到bulid>dev-server.js,然后打开 2:在里面加入这段代码. var app = express() var appDa

优雅的 laravel(1)- Composer概述及其自动加载探秘

刚开始接触laravel,一天时间走马观花的看了一些官方文档之后便开始了laravel的学习.这里谈到的都是最基础的东西,各路大神,可直接略过. composer概述 一开始,最吸引我的当属 Composer 了,因为之前从没用过 Composer . Composer 是PHP中用来管理依赖关系的工具,你只需在自己的项目中声明所依赖的外部工具库,Composer就会帮你安装这些依赖的库文件.运行 Composer 需要 PHP 5.3.2+ 以上版本. 使用composer 第一步,声明依赖关

laravel的源码解析:PHP自动加载功能原理解析

前言 这篇文章是对PHP自动加载功能的一个总结,内容涉及PHP的自动加载功能.PHP的命名空间.PHP的PSR0与PSR4标准等内容. 一.PHP自动加载功能 PHP自动加载功能的由来 在PHP开发过程中,如果希望从外部引入一个 class,通常会使用 include 和 require 方法,去把定义这个 class 的文件包含进来.这个在小规模开发的时候,没什么大问题.但在大型的开发项目中,使用这种方式会带来一些隐含的问题:如果一个 PHP 文件需要使用很多其它类,那么就需要很多的 requ