Bootstrap

12-Composer的配置与使用详解

1、自定义类与非类的自动加载与测试


# composer

> php 包管理工具 ,类似npm

1.自己写的类,函数,接口,常量等全局成员,通过自动加载来实现按需加载
2.自己写的代码,有哪些依赖,用到了哪些外部成员,我自己知道,可以自己管理
3.如果第三方(别人写的),由包管理工具,实现自动加载以及包之间的依赖的处理
4.php中用的是`composer`来实现这个功能,类似于Apple Store,手机应用的商店

## 1.自动加载器

1. `composer init`:交互式创建配置文件 `composer,json`
2. 创建成功后,可以在`vendor/`下面有一个`autoload.php`的自动加载器

## 2.自动加载我自己写的类
> 我自己写的类,依赖关系我自己处理,能不能加载?可以,就用composer就可以

> 这个类文件叫composer.json
```json
{ : {
        "classmap":[
            "inc/",
            "MyClass.php"
        ]
    }
}
```

每一步写完要执行`composer dumpautoload`使之注册并生效
## 3.自动加载我自己写的其它文件
> 注意:文件中的成员必须是全局的才可以自动加载和使用
> 哪些是全局代码(要用空间访问的):类,接口,trait,函数,常量(变量不是,变量有作用域的)
> 配置文件(例如连接数据库的文件):`config/connect.php`
> 公共函数库:`lib/helper.php`

## 4.PSR-4 自动加载功能

### psr(php推荐标准)-4

1.专用于**类**的自动加载
2.`类空间`与`类路径`存在映射关系
3.`类名`与`类文件`同名
4.支持`空间分级`(顶层空间/子空间/自动查询)管理

> 命名空间与类路径名称不一定相同
> 类泛指类:class/interface/trait
> 注意:对象的模板是类,类的模板是接口

## 5.加载第三方的包(只有这个是必须用composer)
> 第三方包(也属于全局成员)的依赖关系,由 composer 进行处理

1.composer.json:`"require":{...}`,`composer install`
2.新建终端输入`composer require 包名`,会自动更新 composer.json
3.都会自动创建`composer.lock`锁定当前版本
4.`composer create-project topthink/think blog`:通过包来创建完整项目

## 6.总结

1.自动加载
2.依赖管理

2、composer的使用

 2-1 首先进入当前命名空间,然后使用composer指令

 如此可证明composer安装成功

2-2 使用 composer selfupdate可以对composer版本进行升级 

 

2-3 升级后通过 composer -v  查看composer版本

2-4 对于composer来说,有个非常重要的文件,就是它的配置文件 (composer.json)

该文件包含了项目的依赖和其它的一些元数据

3、composer.json 

如果手动创建了composer.json文件,则使用composer install,代表安装在composer.json中声明的第三方类库,且手动创建的composer.json必须包含有效的json格式{}

或者,直接使用命令composer init,初始化一个配置文件。 

我自己写的类或其它文件:"autoload":{

        "classmap":[],

        "files":[],

        "psr-4":{}

第三方的类:"require":{}

classmap:

把类的映射关系声明到classmap中,当我加载或调用一个我当前还没有加载的类的时候,我用classmap告诉项目,从哪里找这个类。写完以后还需使用指令composer dumpautoload 使对应的autoload_classmap.php完成注册(在array里) 

"classmap":[
    "inc/",
    "MyClass.php"
],

在class可以直接引用文件名,这样相当于文件名下的所有类都被加载进来。

也可以只引用某个文件。 

files:

把非类文件的映射关系声明到files中,当我加载或调用一个我当前还没有加载的非类文件的时候,我用files告诉项目,从哪里找这个文件。写完以后还需使用指令composer dumpautoload 使对应的autoload_files.php完成注册(在array里) 

"files":[
    "config/connect.php",
    "lib/helper.php"
],

4、autoload.php 

系统自动给我们写好的配置文件(相当于自己写的自动加载器)

5、 database.php

连接数据库的参数配置

<?php

//数据库连接参数
return [
    'dsn'=>'mysql:dbname=phpedu',
    'username'=>'root',
    'password'=>'root'
];

6、connect.php

连接文件,用于实现数据库的连接 

<?php

namespace _0823;

use PDO;

//连接数据库

class Db{
    private $db = null;
    public function __construct($dsn,$username,$password)
    {
        $this->db = new PDO($dsn,$username,$password);
    }
    //测试方法
    public function select($sql){
        return $this->db->query($sql)->fetchAll(PDO::FETCH_ASSOC);
    }
}

7、 使用Db类

<?php

namespace _0823;

//验证自己写的函数或其它文件

//加载composer的自动加载器
require 'vendor/autoload.php';

//$dsn,$username,$password声明在database.php文件
//可以用extract这样写,但是没必要
// extract([
//     'dsn' => 'mysql:dbname=phpedu',
//     'username' => 'root',
//     'password' => 'root'
// ]);
extract(require 'config/database.php');
$db = new Db($dsn, $username, $password);

$users = $db->select('select * from user');
foreach($users as $user){
    printf('<pre>%s</pre>',print_r($user,true));
}

var_dump($db);

echo sum(3,4,5,6);

8、任意数量数据求和

<?php

function sum(...$items){
    //也可以用 array_reduce()
    return array_sum($items);
}

9、psr-4

php推荐标准,只能用于类的自动加载,并且要求类空间与类路径存在映射关系, 这一点和手写的自动加载器很像(如果一个类,它的命名空间和路径存在映射关系就可以写一个自动加载器,我们只需要解析一下类的命名空间解析出来里面的内容作为路径,这样就可以把这个类给加载过来了)。

并且类名一定要和类文件名相同。

<?php

//空间名与路径名可以不同,只要正确的映射就可以
namespace phpcn;
//类名与类文件名要一致
class Index
{
    public static function show()
    {
        //魔术常量__METHOD__返回一下当前方法名
        return '方法名:' . __METHOD__;
    }
}

因为反斜线是转义符,所以必须敲两次 

"psr-4": {
    "phpcn\\":"admin/"
}

 

 在命令行使用composer dumpautoload完成对psr4的注册

10、psr-4的(命名)空间分级管理

 在admin文件夹下,新建一个文件夹controller,在controller下再新建文件login.php

<?php

//空间名与路径名可以不同,只要正确的映射就可以
namespace phpcn\controller;
//类名与类文件名要一致
class Login
{
    public static function show()
    {
        //魔术常量__METHOD__返回一下当前方法名
        return '方法名:' . __METHOD__;
    }
}

 然后需要在配置文件中对phpcn\controller空间和Login类的映射进行注册,但是,由于之前我们已经把phpcn作为一个顶层的命名空间路径给注册到admin下面了,那么在admin文件夹下面所有的类文件以及

10、 第三方包与依赖管理

自己写的类或者其它文件可以自己写一个自动加载器而不一定非要用到composer,但是由于第三方包都会遵循composer标准,所以必须要用composer自动加载器,而且很容易进行一些依赖管理。

 

 第一种方法是在composer.json里面的require对象里写入我们要引入的第三方包。

    "require": {
        "gregwar/captcha":"1.1.*",
    }

*代表最新版本 

 最后在终端使用命令composer install把这个包安装到当前项目

 

 第二种方法是直接在命令终端输入指令直接安装。

这两种方法都会自动创建composer.lock锁定当前版本 

 11、验证并使用第三方包

inline指在页面中怎么用,只需要实例化该类然后在需要的位置引用就行了

<?php
require_once 'vendor/autoload.php';

use Gregwar\Captcha\CaptchaBuilder;

$captcha = new CaptchaBuilder();
$captcha->build();

?>
<!DOCTYPE html>
<body>
    <html>
        <meta charset="utf-8" />
    </html>
    <body>
        <h1>Inline Captcha</h1>

        <img src="<?php echo $captcha->inline(); ?>"/><br/>
        Phrase: <?php echo $captcha->getPhrase(); ?>
        
    </body>
</body>

 遇到了一个bug:从 float  到 int 的隐式转换会丢失精度

 

需将$x和$y强制转成int型即可 

  

  12、使用composer基于包创建一个项目

在终端使用命令composer create-project topthink/think blog创建项目,最后的blog是给这个项目文件夹的命名,如果没有blog这个参数,那么这个文件名则为think(即包名)。注意,这里用的不是require指令,而是create-project指令

 

 打开这个项目blog可以发现,当前这个项目是一个完整的框架项目,这里面它有自己的composer.json(配置器),有自己的一个包目录(vendor),框架的源码在vender里面有一个topthink

 13、medoo(加速开发的轻量级PHP数据库框架)

在终端使用composer require catfan/medoo指令进行安装

 

<?php

namespace _0823;

use Medoo\Medoo;
use PDO;

require 'vendor/autoload.php';

$opt = [
	'type' => 'mysql',
	'host' => 'localhost',
	'database' => 'phpedu',
	'username' => 'root',
	'password' => 'root',
];

$db =  new Medoo($opt);
//查询
// $staffs = $db->select('staff','*');
// print_r($staffs);

//查询(原生PDO操作)
// '?'处不能直接传3,因为会当字符串处理,需要做一个绑定
$stmt = $db->pdo->prepare('select * from staff limit ?');
$stmt->bindValue(1,3,PDO::PARAM_INT);
$stmt->execute();
printf("<pre>%s</pre>",print_r($stmt->fetchAll(PDO::FETCH_ASSOC),true));

上述运行结果: 

 

Array
(
    [0] => Array
        (
            [id] => 1
            [name] => admin
            [sex] => 1
            [email] => [email protected]
        )

    [1] => Array
        (
            [id] => 2
            [name] => 杨过
            [sex] => 1
            [email] => [email protected]
        )

    [2] => Array
        (
            [id] => 3
            [name] => 小龙女
            [sex] => 0
            [email] => [email protected]
        )

)
;