Laravel学习笔记之Composer自动加载

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

注:上篇文章基于Laravel Task-Scheduler定时发送邮件小程序聊到本打算接下来聊聊Laravel的设计模式,不过做者水平有限还需提升一段时间,故暂不先误人子弟了。此次先一块儿聊聊Composer的自动加载机制,并以Laravel的Container为例举例。html

Composer的自动加载机制

一、初始化一个composer项目
在一个空目录下composer安装Laravel的容器Container包:laravel

composer require illuminate/container

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

<?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);

二、分析下composer加载类的流程
图片描述小程序

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

Composer按照四种规范来加载文件:设计模式

  • psr-4api

  • psr-0(这种规范某些部分不是很优雅)数组

  • classmap(命名空间和文件路径的映射)app

  • 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包只包含IlluminateContainer和IlluminateContracts,且都是psr-4规范,则私有变量$prefixLengthsPsr4和$prefixDirsPsr4就包含了命名空间路径映射的数组值,其他私有变量就是空。

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

Container类的实例化过程

图片描述

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

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

总之,当实例化一个类时,这个$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的IlluminateContainer包为例具体说明实例化类时是如何找到其文件的,并讲述如何自定义本身的类并经过Composer来注册和加载。过两天还想结合PHP的字符串和数组这些基础知识新开篇章,到时见。

欢迎关注Laravel-China

RightCapital招聘Laravel DevOps

相关文章
相关标签/搜索