自动加载

composer (一) – 依赖管理 前面这篇文章介绍了 composer 对依赖的安装及更新。

composer (二) – 第三方包使用 这篇文章记录了如何使用一个第三方类。

这次介绍下 composer 的自动加载机制。

自动加载机制到目前有了很多个标准,目前使用最多的是 PSR-4 标准,4 版本之前的标准已经被弃用了。psr-4自动加载规范

当我们安装了依赖或者进行更新以及创建一个新的项目时,在 vendor 包中总是会生成一个 autoload.php 文件,这个文件就是用来记录并规范自动加载的配置文件。

查看 autoload.php 文件

1
2
3
4
# autoload.php
require_once __DIR__ . '/composer/autoload_real.php';

return ComposerAutoloaderInitc5a08d4f09af4fb49c6b4dce16426448::getLoader();

可以看到加载了真正的 autoload_real.php 文件,并返回一个加载器方法。

继续追溯这个 getLoader() 方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# composer/autoload_real.php
# getLoader()
public static function getLoader()
    {
        if (null !== self::$loader) {
            return self::$loader;
        }
    ...
        $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);
            }
    ...

其中最关键的就是 $map 那几行代码,定义了三种自动加载的方案。

1.namespace 2.psr4 3 classmap

所以在使用所有的第三方包或者框架时,都会加载这个文件,大部分框架已经在初始化时加载进来了,不需要我们在使用时每次都手动加载 require_once __DIR__ . 'vendor/autoload.php'

Psr4 加载

首先打开 vendor/composer/autoload_psr4.php ,这里是 psr4 规范所对应的自动加载规则

1
2
3
4
5
# autoload_psr4.php
return array(
    'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
    'Monolog\\' => array($vendorDir . '/monolog/monolog/src/Monolog'),
);

可以看到,psr 通过关联数组的方式将类名与包源码所对应起来。

monolog 是如何自动加载到这个数组中的呢?

我们找到 monolog/src/monolog/composer.json 文件,可以看到 autoload 属性。

1
2
3
4
5
6
7
# composer.json
 "autoload": {
        "psr-4": {"Monolog\\": "src/Monolog"}
  },
 "autoload-dev": {
        "psr-4": {"Monolog\\": "tests/Monolog"}
  },

可以看到,这里指定了自动加载的方式以及对应关系。当安装或更新依赖时,就会自动更新这些依赖的加载。

使用 psr4 引入自定义 class

通过上面的 monolog 可以发现,只要在 composer.json 文件中定义自动加载方式及对应关系,生成自动加载文件就可以了。开始试验。

首先在项目目录下新建目录和文件:

1
2
3
4
5
6
7
8
App
├── Controllers
│   └── UserController.php
└── Models
    └── User.php
...
├── composer.json
├── test.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# UserController.php
<?php

namespace App\Controllers;

class UserController
{
    function __construct()
    {
        echo "user controller autoload";
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# User.php
<?php

namespace App\Models;

class User
{
    function __construct()
    {
        echo "user model autoload";
    }
}

1
2
3
4
5
6
7
8
# test.php
<?php

require 'vendor/autoload.php';

use App\Controllers\UserController;

$usercontroller = new UserController();

修改 composer.json 文件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
	"name": "caoayu/composer",
	"description": "composer",
	"require": {
		"monolog/monolog": "^2.2"
	},
	"autoload": {
		"psr-4": {"App\\":"App"}
	}
}

更新自动加载文件

1
composer dump-autoload

运行 test.php 文件:

1
2
php test.php
# user controller autoload

注意,psr4 的方式规定类的命名空间一定要与类的目录结构对应,在 Linux 上,文件名是区分大小写的,所以命名空间的大小写也是不一样的。尽量在每个平台都保持统一