composer 的设计原理及其基本用法

相信有在用PHP的朋友近年来常听到composer这个套件管理工具。它究竟是作什么用的?又是为了解决什么问题而存在呢?javascript

要了解这个,得先从历史开始提及…。php

PHP最先加载类的方法

初学PHP时,最先会面对的问题之一就是require与include差异何在?
require_once与include_once又是什么?java

弄懂这些问题以后,若是不使用framework,直接开发,便常出现相似这样的code:web

// whatever.php // 这档案须要用到几个类别 require 'xxx_class.php'; require 'yyy_class.php'; require 'zzz_class.php'; // ... 

而后在其余档案会出现:json

// another.php // 这档案须要用到几个类别 require 'yyy_class.php'; require 'zzz_class.php'; // ... 

这样的结果,会产生至少两个问题:api

  1. 许多档案用到一样几个class,因而在不一样地方都须要载入一次。
  2. 当类别多了起来,会显得很乱、忘记载入时还会出现error。

那么,不如试试一种懒惰的做法?composer

写一个php,负责载入全部类别:工具

// load_everything.php require 'xxx_class.php'; require 'yyy_class.php'; require 'zzz_class.php'; require 'aaa_class.php'; require 'bbb_class.php'; require 'ccc_class.php'; 

而后在其余档案都载入这支档案便可:ui

require 'load_everything.php' 

结果新问题又来了:当类别不少的时候,随便一个web page都会载入一堆code,占用大量内存,怎么办呢?google

__autoload

为解决这个问题,PHP 5开始提供__autoload这种俗称“magic method”的函式。

当你要使用的类别PHP找不到时,它会将类别名称当成字串丢进这个函式,在PHP喷error投降以前,作最后的尝试:

// autoload.php function __autoload($classname) {     if ($classname === 'xxx.php'){         $filename = "./". $classname .".php";         include_once($filename);     } else if ($classname === 'yyy.php'){         $filename = "./other_library/". $classname .".php";         include_once($filename);     } else if ($classname === 'zzz.php'){         $filename = "./my_library/". $classname .".php";         include_once($filename);     }     // blah } 

也由于PHP这种“投降前最后一次尝试”的行为,有时会让没注意到的人困惑“奇怪个人code怎么跑得动?我根本没有require啊..”,因此被称为“magic method”。

如此一来,问题彷佛解决了?

惋惜仍是有小缺点..,就是这个__autoload函式内容会变得很巨大。以上面的例子来讲,一下会去根目录找、一下会去other_library资料夹、一下会去my_library资料夹寻找。在整理档案的时候,显得有些混乱。

spl_autoload_register

因而PHP从5.1.2开始,多提供了一个函式。

能够多写几个autoload函式,而后注册起来,效果跟直接使用__autoload相同。

如今能够针对不一样用途的类别,分批autoload了。

spl_autoload_register('my_library_loader'); spl_autoload_register('other_library_loader'); spl_autoload_register('basic_loader'); function my_library_loader($classname) {     $filename = "./my_library/". $classname .".php";     include_once($filename); } function other_library_loader($classname) {     $filename = "./other_library/". $classname .".php";     include_once($filename); } function basic_loader($classname) {     $filename = "./". $classname .".php";     include_once($filename); } 

每一个loader内容能够作不少变化。能够多写判断式让它更智慧、能够进行字串处理…。

自动载入类别的问题终于解决了…。

可是光上面的code也有15行,并且在每一个project必定都会写相似的东西。有没有办法自动产生这15行呢?

个人愿望很简单,我告诉你,反正我有my_library资料夹跟other_library资料夹,你本身进去看到什么类别就所有载入好很差…?

阿不对,所有载入刚又说效能很差,那你进去看到什么就所有想办法用spl_autoload_register记起来好很差…?

我懒得打15行了,我只想打这几个字:

$please_autoload  =  array( 'my_library', 'other_library'); 

可不能够发明一个工具,去执行$please_autoload这个变数,而后本身想办法载入一切啊…?

等等,我连php程式码都懒得打了,在web领域JSON格式更简洁。容许我这样打,好吗?

{
    "autoload": [         "my_library",         "other_library"     ] } 

而后谁来个工具帮我产生一大串autoload相关的php程式码吧…,能够吗?

能够。

Composer登场

首先,装好composer(本文不介绍如何安装。)

我将会在其余博客中介绍composer安装,及如何在天朝这种大局域网内使用。

再来,创建一个composer.json档,里面输入这些:

{
    "autoload": {         "classmap": [             "my_library",             "other_library"         ]     } } 

比本来但愿的多打了一些字,不过差很少。

再来,在terminal输入 composer install

执行成功以后,你会看到一个vendor资料夹,内含一个autoload.php。

没错,跟你梦想的同样。你只要载入这个档案:

require 'vendor/autoload.php'; 

你须要的全部类别,都会在适当的时候、以适当的方式自动载入。
php不再会error说你“类别还没有定义”了!

这vendor资料夹里面的一切,都只是php code而已,并无特别神奇的地方。只要去看autoload.php的原始码,就能知道composer到底写了哪些php code给你。

等等,我写的类别都放在my_library里面了,other_library都是网路上copy下来的现成类别。我想要用Google API的Client类别、Doctrine资料库管理抽象层类别、还有guzzlehttp的发送request类别。

我连去下载这些档案、而后丢进这个资料夹都懒得作了,我根本不想手动创建other_library这个资料夹。composer真那么神…不如连下载都帮我自动下载?能够吗?

能够。

查询一下那几个套件在“https://packagist.org/”的名称、还有你须要的版本号。

把刚刚的composer.json改为这样:

{
    "require": {         "google/apiclient": "1.0.*@beta",         "guzzlehttp/guzzle": "~4.0",         "doctrine/dbal": "~2.4"     },     "autoload": {         "classmap": [             "my_library"         ]     } } 

而后’composer install’指令除了自动载入你的类别以外、还会自动下载你须要的类别、而后自动载入它们。

同样require ‘vendor/autoload.php’就能够了。composer实在是太棒了。

其实composer解决的问题不仅这样。

类别多了起来以后,各类程式语言都提供namespace功能协助分类。

在有namespace的状况下,PHP社群与composer是如何解决自动载入的问题呢?

这些比较进阶的内容,下回分晓。

转载地址

http://blog.turn.tw/?paged=4&cat=2

相关文章
相关标签/搜索