PHP|组件、依赖管理和自动加载

434 查看

组件

PHP组件目录Packagist

https://packagist.org

使用组件

Packagist是查找PHP组件的地方,Composer是安装PHP组件的工具

https://getcomposer.org

安装:

curl -sS https://getcomposer.org/installer | php

使用curl下载Composer的安装脚本,使用PHP执行安装脚本,最后在当前目录中创建composer.phar文件

有用的一条命令:

sudo mv composer.phar /usr/local/bin/composer

把composer编程可执行的二进制文件:

sudo chmod +x /usr/local/bin/composer

~/.bash_profile中添加下面这行代码:

PATH=/usr/local/bin:$PATH

命令行中执行composer. Bingo

安装组件

进入项目的最顶层目录,然后为每个PHP组件执行一次:

composer require vendor/package

这个命令可以安装这个组件的最新稳定版。

执行命令的接轨哦可以在项目最顶层目录中新建或更新的composer.json文件中查看。执行这个命令后还会创建一个composer.lock文件。

composer.lock

这个文件会列出项目使用的所有PHP组件,以及组件的具体版本号。这其实是锁定了项目,让项目只能使用具体版本的PHP组件。

Why? 如果有composer.lock文件,Composer会下载这个文件中列出的具体版本,而不管Packagist中可用的最新八本是多少。所以,应该把composer.lock文件纳入版本控制,让大家使用相同版本的PHP组件。

composer.lock有个缺点,composer install命令不会安装避其中列出的版本号新的版本。如果需要下载新版组件,需要使用

composer update

自动加载PHP组件

我们只需在scan.php文件的顶部使用require函数导入Composer创建的自动加载器:

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

Composer创建的自动加载器就是名为autoload.php的文件。这样我们就可以在项目中实例化任何组件。

举个例子:编写scan.php

通过Guzzle和CSV组件编写scan.php脚本。

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

$client = new \GuzzleHttp\Client();
$csv = new \League\Csv\Reader($argv[1]);
foreach ($csv as $csvRow) {
    try {
        $httpResponse = $client->options($csvRow[0]);
        
        if ($httpResponse->getStatusCode >= 400) {
            throw new \Exception();
        }
    } catch (\Exception $e) {
        echo $csvRow[0] . PHP_EOL;
    }
}

实例化组件时,这里使用了\GuzzleHttp & \League\Csv命名空间。

执行:

php scan.php urls.csv

使用PHP编写命令行脚本

Composer和私有库

Composer可以管理放在需要认证的仓库中的私有组件。

执行composer install or composer update时,如果需要认证,Composer会提醒你。

Composer还会询问你是否把仓库的认证保存在本地的auth.json文件中。

auth.json:

{
    "http-basic": {
        "example.org": {
            "username": "",
            "password": ""
        }
    }
}

如果不想等Composer向你询问认证凭据,使用下述命令:

composer config http-basic.example.org your-username your-password

解释一下:http-basic告诉Composer,我们要为指定的域名天假认证信息,example.org是主机名。这个命令会在当前项目中的auth.json文件里保存凭据。

创建组件

文件系统的组织方式

src/
tests/
composer.json
README.md
CONTRIBUTING.md
LICENSE
CHANGELOG.md

Demo: https://github.com/thephpleague/skeleton

composer.json

举个例子:

{
    "name": "vendor/package",
    "description": "",
    "keywords": ["", ""],
    "homepage": "http://example.org",
    "license": "MIT",
    "authors": [
        {
            "name": "",
            "homepage": "",
            "role": "Developer"
        }
    ],
    "support": {
        "email": ""
    },
    "require": {
        "php": ">=5.4.0",
        "vendorX/packageX": "~5.0"
    },
    "require-dev": {
        "vendorY/packageY": "~4.3"
    },
    "suggest": {
        "league/csv": "~6.0"
    },
    "autoload": {
        "psr-4": {
            "namespace\\subnamespace\\": "src/"
        }
    }
}

其中:

support的对象是建议安装的组件,以防与其他组件合作时需要。

autoload: 在PSR-4中,我们要把组件的命名空间前缀与相对组件根目录的文件系统路径对应起来。

如果实例化虚构的namespace\subnamespace\Url\Scanner类,Composer会自动加载src/Url/Scanner.php文件。

Demo: http://getcomposer.org

README

  • 组件的名称和描述

  • 安装说明

  • 用法说明

  • 测试说明

  • 贡献方式说明

  • 支持资源

  • 作者信息

  • 软件许可证

实现组件

Demo

<?php
namespace namespace\subnamespace\Url;

class Scanner
{
    protected $urls;
    
    /** @var \GuzzleHttp\Client */
    protected $httpClient;
    
    public function __construct(array $urls)
    {
        $this->urls = $urls;
        $this->httpClient = new \GuzzleHttp\Client();
    }
    
    public function getInvalidUrls()
    {
        $invalidUrls = [];
        foreach ($this->urls as $url) {
            try {
                $statusCode = $this->getStatusCodeForUrl($url);
            } catch (\Exception $e) {
                $statusCode = 500;
            }
            
            if ($statusCode >= 400) {
                array_push($invalidUrls, [
                    'url' => $url,
                    'status' => $statusCode
                ]);
            }
        }
        
        return $invalidUrls;
    }
    
    protected function getStatusCodeForUrl($url)
    {
        $httpResponse = $this->httpClient->options($url);
        
        return $httpResponse->getStatusCode();
    }
}

提交

  1. 提交代码到自己的github上

  2. 提交组件到 https://packagist.org/packages/submit

  3. 可以通过设置钩子,每次更新组件的repo时,通知Packagist: https://packagist.org/profile/

  4. 使用: composer require vendor/package

<?php
require 'vendor/autoload.php';
$urls = [
    'http://php.net',
    'http://apple.com'
];

$scanner = new \namespace\subnamespace\Url\Scanner($urls);
print_r($scanner->getInvalidUrls());

参考

  1. Modern PHP