传统的 PHP,拿别人写好的代码来用,一般是要把别人的文件放到某个位置,然后在自己的代码里引入这个文件,再调试,直到成功,花了挺多功夫。有了面向对象后,最好的习惯是一个类一个文件,然后你就需要一个文件引入一次,很麻烦。

自从有了 composer 后,这种问题就没那么麻烦了,下面将会介绍几种类加载方法。

psr-4

2amigos/yii2-qrcode-helper 的 composer.json 为例。

composer 安装下来后,目录为 vendor/2amigos/yii2-qrcode-helper,以下提到的路径都是该目录的相对路径

看看他们的类加载:

{
    "autoload": {
        "psr-4": {
            "dosamigos\\qrcode\\": "src"
        }
    }
}

再看一下他们的 QrCode 类,路径为 src/QrCode.php,命名空间是 dosamigos\qrcode

爱动脑的你一定看出来了,这个包注册了 dosamigos\qrcode 这个命名空间,对应的路径是它的 src 目录,这个路径可以理解成是 composer.json 的相对路径(如果是相同目录就留空),当你调用了命名空间开头为 dosamigos\qrcode 的类,composer 就会去 src 这个目录寻找文件名与类名相符的 php 文件

举个具体的例子:当你代码在调用 dosamigos\qrcode\a\b\Test 类时,composer 就会去 vendor/2amigos/yii2-qrcode-helper/src/a/b 目录来寻找 Test.php 文件。

同理,你也可以在项目里建立一个 composer.json 文件,根据你的需求配好 autoload 之后,执行 composer dump-autoload 命令,然后把 vendor/autoload.php 文件用 require 引入到你的代码里,以后只要自己的类放在特定的目录并使用特定的命名空间,就不需要一个一个引入进来了。例如 Laravel 框架就是以 App 命名空间来加载 app 目录下的类的。

最后,你还可以去 vendor/composer/autoload_psr4.php 文件看一下配置了多少个加载。

classmap

这种加载方式应该会更简单,但是我觉得不如 psr-4 的方法规范,首先你在 composer.json 加上以下代码:

{
    "autoload": {
        "classmap": [
            "dir/dir/dir",
            "xx/xx/file.php"
        ]
    }
}

然后你可以在你配置的目录或者文件里创建各种类,命名空间随意,类数量不限,创建好类之后执行一下 composer dump-autoload 命令,把 vendor/autoload.php 文件 require 到你的代码里就能用了,如果以后新建或修改类后报错找不到类尝试重新执行一下这个命令。

最后,你还可以去 vendor/composer/autoload_classmap.php 文件看一下配置了多少个加载。

files

这种加载方式一般用来加载全局函数,首先你可以在 composer.json 加上以下代码:

{
    "autoload": {
        "files": [
            "xx/xx/GlobalFunctions.php"
        ]
    }
}

执行一下 composer dump-autoload 命令并把 vendor/autoload.php 文件 require 到你的代码里就能用了,然后你可以在指定的文件里封装你喜欢的函数,但建议在函数外加一层 if (!function_exists('functionName')) 来判断该函数是否存在。

最后,你还可以去 vendor/composer/autoload_files.php 文件看一下配置了多少个加载。

附:yii2 框架的类加载

yii2 本身也有类加载,不依赖 composer(所以 yii2 项目的 composer.json 文件可以说是通用的,你可以让多个 yii2 项目共享一个 vendor 目录节约空间,我在第二家公司的时候就是这么干的)。

其实官方的文档已经说的很明白了,你可以去看。

你要是看懂上面 composer 的 psr-4 的方法,那么 yii2 的类加载也挺好理解的,比如我注册了一个别名 @asdf,这个别名的值是我某目录的路径:

Yii::setAlias('@asdf', 'path/to/asdf');

当我调用 \asdf\a\b\Test 类时,命名空间的开头是 asdf,框架就会根据别名 @asdf/a/b/Test.php 来寻找这个类,把别名转换成对应的值就是路径 path/to/asdf/a/b/Test.php 了。

框架自带了一个别名叫 @app,它的值和 yii\base\Application::$basePath 一致,一般情况下这个值就是应用的根目录,比如 basic 模板里的类基本都是在 app 命名空间下的,advanced 模板则会把应用分为 @frontend@backend,以及公共目录 @common,你看一下这些目录里类的命名空间和路径就明白了。