composer基础与实践-中篇
在composer基础与实践-上篇中,通过require命令就能方便的引入第三方开源代码,同时我们也编写了一个index.php入口文件引入了vender/autoload.php,从而可以直接使用通过composer安装的各种类而不需要显式的include文件。
接下来,我继续给项目编写一个自己的基础库,并且通过编写composer.json,让composer帮我”自动加载”这个基础库,这个过程中将会了解几种composer的”自动加载”规范,不仅可以省去自己为项目订制autoload函数的麻烦事,同时也可以让我们理解第三方开源库是如何借助composer进行发布的。
1,继续在project目录下工作,先创建一个common目录,在里面编写一个MyLog.php作为我的基础库,这个类基于第三方的monolog实现,同时该类属于全局命名空间。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
[work@vultr project]$ ll 总用量 1692 drwxrwxr-x 2 work work 4096 8月 8 06:51 common -rw-rw-r-- 1 work work 71 8月 6 15:00 composer.json -rw-rw-r-- 1 work work 5226 8月 6 15:00 composer.lock -rwxr-xr-x 1 work work 1705467 8月 6 14:08 composer.phar -rw-rw-r-- 1 work work 164 8月 8 06:47 index.php drwxrwxr-x 5 work work 4096 8月 6 15:11 vendor [work@vultr project]$ cat common/MyLog.php <?php // composer会找到这个类的,不需要我们操心 use Monolog\Logger; class MyLog { private static $logger_ = null; public static function instance() { if (self::$logger_ == null) { self::$logger_ = new Logger("test"); } return self::$logger_; } public function info($msg) { self::$logger_->info('hello'); } } |
2,在index.php里,通过传统的require命令引入这个文件,从而调用Mylog测试一下功能是否可用。
1 2 3 4 5 6 7 8 9 10 11 12 |
[work@vultr project]$ cat index.php <?php // 引入composer的自动加载文件 require __DIR__ . '/vendor/autoload.php'; require __DIR__ . '/common/MyLog.php'; MyLog::instance()->info('hello'); [work@vultr project]$ php index.php [2016-08-08 06:54:49] test.INFO: hello [] [] |
成功打印出日志,说明Mylog类功能没有问题。
3,现在借助composer,让它帮我们实现Mylog类的自动加载。第一种方法叫做classmap,它对Mylog没有任何命名空间或者目录结构的要求,最基础也最普通。
先编写composer.json增加如下配置,并执行dump-autoload命令,该命令会扫描common目录下所有php文件,并生成类名->文件的映射关系保存到vender/composer/autoload_classmap.php文件中,从而实现自动加载。
1 2 3 4 5 6 7 8 9 10 11 12 |
[work@vultr project]$ cat composer.json { "name": "project", "require": { "monolog/monolog": "1.21.0" }, "autoload": { "classmap": ["common"] } } [work@vultr project]$ php composer.phar dump-autoload Generating autoload files |
可以看一下composer是如何维护映射关系的,其实做法很朴素,一看就懂。
1 2 3 4 5 6 7 8 9 10 11 |
[work@vultr project]$ cat vendor/composer/autoload_classmap.php <?php // autoload_classmap.php @generated by Composer $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( 'MyLog' => $baseDir . '/common/MyLog.php', ); |
下面改一下index.php,注释掉require,依旧可以成功打印log,说明classmap生效。
1 2 3 4 5 6 7 8 9 10 11 12 |
[work@vultr project]$ cat index.php <?php // 引入composer的自动加载文件 require __DIR__ . '/vendor/autoload.php'; //require __DIR__ . '/common/MyLog.php'; MyLog::instance()->info('hello'); [work@vultr project]$ php index.php [2016-08-08 07:11:25] test.INFO: hello [] [] |
4,注意,这里Mylog.php文件名和里面的Mylog类名不强制要求相同,因为classmap原理是扫描目录下文件,识别文件里的类名并建立到文件名的关系。同时,也可以猜测Mylog类处在任意命名空间都是可以被classmap自动加载的,所以现在给Mylog添加一个命名空间common(也可以是其他的)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
[work@vultr project]$ cat common/MyLog.php <?php namespace common; // composer会找到这个类的,不需要我们操心 use Monolog\Logger; class MyLog { private static $logger_ = null; public static function instance() { if (self::$logger_ == null) { self::$logger_ = new Logger("test"); } return self::$logger_; } public function info($msg) { self::$logger_->info('hello'); } } |
然后,重新执行composer的dump-autoload以便重新扫描目录生成新的映射关系。最后我们修改index.php,use引入common\Mylog并调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
[work@vultr project]$ php composer.phar dump-autoload Generating autoload files [work@vultr project]$ cat index.php <?php // 引入composer的自动加载文件 require __DIR__ . '/vendor/autoload.php'; //require __DIR__ . '/common/MyLog.php'; use common\MyLog; MyLog::instance()->info('hello'); [work@vultr project]$ php index.php [2016-08-08 07:32:50] test.INFO: hello [] [] |
调用成功,我们再看看autoload_classmap.php文件,映射的Key变成了带命名空间的Mylog,合情合理。
1 2 3 4 5 6 7 8 9 10 |
<?php // autoload_classmap.php @generated by Composer $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( 'common\\MyLog' => $baseDir . '/common/MyLog.php', ); |
5,classmap的优势在于:已有的类可以很方便的通过composer引入,并且对命名空间,文件名称,目录结构无强制要求。但是classmap只是用来引入class的,如果我们项目里有一些函数文件或者常量定义的文件,那么classmap是无法支持的。
所以,这里需要用到另一种加载方式autoload_files,只需要把要加载的文件直接列出来,composer会帮我们一次性全量加载,而不是按需自动加载,当然,composer也不在乎文件里写的到底是函数,常量或者混合情况。
下面继续在common下编写一个func.php基础库文件,里面定义了一个类,一个函数,一个常量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
[work@vultr project]$ cat common/func.php <?php class SomeClass { function __construct() { echo __CLASS__ . "\n"; } } function some_func() { echo __FUNCTION__ . "\n"; } const SOME_DEF = "this is a def\n"; |
然后修改composer.json,通过files配置引入func.php。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
[work@vultr project]$ cat composer.json { "name": "project", "require": { "monolog/monolog": "1.21.0" }, "autoload": { "classmap": ["common"], "files": ["common/func.php"] } } [work@vultr project]$ php composer.phar dump-autoload Generating autoload files |
现在修改index.php,访问一下类,函数,常量均可以成功,说明vender/autoload.php帮我们把func.php文件一次性引入了进来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
[work@vultr project]$ cat index.php <?php // 引入composer的自动加载文件 require __DIR__ . '/vendor/autoload.php'; //require __DIR__ . '/common/MyLog.php'; use common\MyLog; MyLog::instance()->info('hello'); new SomeClass(); some_func(); echo SOME_DEF; [work@vultr project]$ php index.php [2016-08-08 08:11:49] test.INFO: hello [] [] SomeClass some_func this is a def |
看看composer生成的映射关系,就是列举了一下需要一次性引入的文件列表。
1 2 3 4 5 6 7 8 9 10 11 |
[work@vultr project]$ cat vendor/composer/autoload_files.php <?php // autoload_files.php @generated by Composer $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( '30065628ccdef92580e1a4d215d845d1' => $baseDir . '/common/func.php', ); |
有意思的是,因为classmap存在的关系,func.php里的SomeClass被扫描到了autoload_classmap.php中,这并不影响正常工作。
1 2 3 4 5 6 7 8 9 10 11 12 |
[work@vultr project]$ cat vendor/composer/autoload_classmap.php <?php // autoload_classmap.php @generated by Composer $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( 'SomeClass' => $baseDir . '/common/func.php', 'common\\MyLog' => $baseDir . '/common/MyLog.php', ); |
通过本篇的实践,应该掌握通过autoload classmap/files来实现项目文件的自动加载,一般情况下这两个方法足够项目使用了。在下篇中,将会简单的了解psr-0和psr-4两种自动加载的标准规范,它们对目录结构,命名空间有严格的要求,是composer推荐用法。
如果文章帮助您解决了工作难题,您可以帮我点击屏幕上的任意广告,或者赞助少量费用来支持我的持续创作,谢谢~
