Composer是 PHP 用来管理依赖(dependency)关系的工具。你可以在自己的项目中声明所依赖的外部工具库(libraries),Composer 会帮你安装这些依赖的库文件。
PHP中常用扩展库模式PK
项目中常用的Composer代码包
包名 | 说明 | 地址 |
---|---|---|
guzzlehttp/guzzle | 功能强大的 HTTP 请求库 | https://packagist.org/packages/guzzlehttp/guzzle |
hashids/hashids | 数字 ID 转字符串,支持多语言 | https://packagist.org/packages/hashids/hashids |
intervention/image | 图片处理,获取图片信息,上传,格式转换,缩放,裁剪等 | https://packagist.org/packages/intervention/image |
phpmailer/phpmailer | 邮件发送 | https://packagist.org/packages/phpmailer/phpmailer |
phpoffice/phpexcel | excel操作类 | https://packagist.org/packages/phpoffice/phpexcel |
monolog/monolog | 日志操作,composer官方就是用它做例子 | https://packagist.org/packages/monolog/monolog |
catfan/medoo | 简单易用的数据库操作类,支持各种常见数据库 | https://packagist.org/packages/catfan/medoo |
league/route | 路由调度 | https://packagist.org/packages/league/route |
nesbot/carbon | 时间操作 | https://packagist.org/packages/nesbot/carbon |
require("vendor/autoload.php");
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
// create a log channel
$log = new Logger('name');
$log->pushHandler(new StreamHandler(__DIR__.'/your.log', Logger::WARNING));
// add records to the log
$log->warning('this is a test');
$log->error('ok');
键名 | 描述 |
---|---|
name | 表示包的名称,如果你经常使用 Github, 那对这个值的表达式一定非常熟悉. 通常扩展包名包含两部分,并且以"/"分割.斜杠前的部分,代表包的所有者,斜杠后的部分代表包的名称.尽量保持简单和有意义,便于记忆和传播. 如 “name”:“Lmonkey/demo”, "Lmonkey"表示公司, “demo” 表示公司下面的一个项目名 |
description | 表示项目的应用简介,这部分应尽量简洁的介绍项目.如果确实有很多内容,建议写在 README.md 文件里(在扩展库的源码目录中) |
license | 如果决定将包公开发布,那么记得选择一个合适的许可证.这样别的程序员在引用包的时候,通过查看许可证,确保没有法律上的问题. |
authors | 作者字段可以包含一个对象数组,也就是说,可以提供多个作者信息. |
require | 这个字段的值是一个对象,同样以键值对的形式构成.上例提到的两个依赖关系,最重要的就是版本信息的指定.如我们需要使用monolog的版本是1.0.,意思是只要版本是1.0分支即可,如1.0.0, 1.0.2或1.0.99. 版本定义的几种方式如下: ①标准的版本: 定义标准的版本包文件,如1.0.2 ②一定范围的版本: 使用比较符号来定义有效的版本的范围,有效的符号有>,>=,<,<=,!= ③通配符:特别的匹配符号, 如1.0.* 相当于>=1.0且<1.1版本即可 ④下一个重要的版本: ~符号最好的解释就是, ~1.2就相当于>1.2 且<2.0, 但~1.2.3相当于 >=1.2.3且<1.3版本 |
minimum-stability | 通过设置minimum-stablility的值,告诉Composer当前开发的项目依赖要求的包的全局稳定性级别,它的值包括dev,alpha,beta,RC,stable, 其中,stable是默认值 |
文件composer.lock 会根据 composer.json 的内容自动生成, 和 composer.json 在同一位置, 即在安装完所有需要的包之后, Composer 会在 composer.lock文件中生成一张标准的包版本的文件,这将锁定所有包的版本. 可以使用 composer.lock (当然是和 composer.json 一起) 来控制项目的版本.
composer.lock 与 composer.json 的关系为: composer.json 文件为包的元信息, composer.lock 文件同样为包的元信息, 但在 composer.json文件中可以指定不明确的依赖包版本, 如 “>=1.0” , 在 componser.lock 文件中的会是当前安装的版本.那么当使用 Componser安装包时,它会优先从composer.lock 文件读取依赖版本,再根据 composer.json 文件去获取依赖.这确保了该库的每个使用者都能得到相同的依赖版本.这对于团队开发来讲非常重要.
命令 | 描述 |
---|---|
composer list | 获取帮助信息 |
composer init | 以交互方式填写 composer.json 文件信息 |
composer install | 从当前目录读取 composer.json 文件,处理依赖关系,并安装到 vendor 目录下 |
composer update | 获取依赖的最新版本,升级 composer.lock 文件 |
composer require | 添加新的依赖包到 composer.json 文件中并执行更新 |
composer search | 在当前项目中搜索依赖包 |
composer show | 列举所有可用的资源包 |
composer validate | 检测 composer.json 文件是否有效 |
composer self-update | 将 composer 工具更新到最新版本 |
composer create-project | 基于 composer 创建一个新的项目 |
更新一个插件的版本号
{
"require": {
"monolog/monolog": "1.25.0"
}
}
composer update monolog/monolog
composer require noahbuscher/macaw:dev-master
在index.php 加入如下代码
require('vendor/autoload.php');
use NoahBuscher\Macaw\Macaw;
// 打开首页测试
Macaw::get('/', function () {
echo "this is index";
});
// 访问 http://xx.com/hello
Macaw::get("/hello", function () {
echo "hello,world!";
});
// 访问 http://bd.del.com/demo/22
Macaw::get("/demo/(:num)", function ($id) {
echo "#######{$id}";
});
Macaw::dispatch();
打开网址,即可显示.
namespace controllers;
class Test
{
function index()
{
echo "this is index()";
}
function hello(){
echo "this is hello()";
}
}
require('vendor/autoload.php');
use NoahBuscher\Macaw\Macaw;
Macaw::get('/index', "controllers\Test@index");
Macaw::dispatch();
{
"require": {
"monolog/monolog": "2.1.1",
"noahbuscher/macaw": "dev-master"
},
"autoload": {
"classmap": [
"app/controllers"
]
}
}
如上成功了, 我们在 vendor / composer 下面的 autoload_classmap.php 下,就可以看到,我们自己写的 Hello,Test就已经加载了
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'controllers\\Hello' => $baseDir . '/app/controllers/Hello.php',
'controllers\\Test' => $baseDir . '/app/controllers/Test.php',
);
如上, 我们手动的 composer dump-autoload 的方式来加载我们的控制器,这样是可以的,但是如果项目太大,这样是不够的. 应该想办法实现自动加载.
{
"require": {
"monolog/monolog": "2.1.1",
"noahbuscher/macaw": "dev-master"
},
"autoload": {
"psr-4": {
"controllers\\": "app/controllers/"
}
}
}
如上修改, 则可以自动加载类,不需要手动 composer dump-autoload. 此时,在 vendor/composer/autoload_psr4.php 中可以看到 contorllers的配置.
// +----------------------------------------------------------------------
// | User: zq
// +----------------------------------------------------------------------
// | Time: 2020/10/28 3:10 下午
// +----------------------------------------------------------------------
namespace controllers;
class BaseController
{
//成功之后
function success($url, $msg)
{
echo "";
}
//失败之后
function error($url, $msg)
{
echo "";
}
}
class Test extends BaseController
// +----------------------------------------------------------------------
// | User: zq
// +----------------------------------------------------------------------
// | Time: 2020/10/28 3:18 下午
// +----------------------------------------------------------------------
// 自动加载文件, 其中的方法,在控制器,模型等,所有的位置都可以用
// 因为这里没有命名空间,所以为了防止重复,最好做一个判断
if (!function_exists("dd")) {
function dd(...$args)
{
http_response_code("500");
foreach ($args as $x) {
var_dump($x);
}
die(1);
}
}
{
"require": {
"monolog/monolog": "2.1.1",
"noahbuscher/macaw": "dev-master"
},
"autoload": {
"psr-4": {
"controllers\\": "app/controllers/"
},
"files": [
"app/helpers.php"
]
}
}
// +----------------------------------------------------------------------
// | User: zq
// +----------------------------------------------------------------------
// | Time: 2020/10/28 2:38 下午
// +----------------------------------------------------------------------
namespace controllers;
class Test extends BaseController
{
function index()
{
dd("aaaa", array(1, 2, 3, 4));
}
}
浏览器打开, 可以输出 string(4) “aaaa” array(4) { [0]=> int(1) [1]=> int(2) [2]=> int(3) [3]=> int(4) } ,没有问题.
require_once '/path/to/vendor/autoload.php';
$loader = new \Twig\Loader\ArrayLoader([
'index' => 'Hello {{ name }}!',
]);
$twig = new \Twig\Environment($loader);
echo $twig->render('index', ['name' => 'Fabien']);
namespace controllers;
class BaseController
{
protected $twig;
protected $data = array();
//构造方法
public function __construct()
{
$loader = new \Twig\Loader\FilesystemLoader(dirname(__DIR__) . '/views/');
$this->twig = new \Twig\Environment($loader, [
//'cache' => '/path/to/compilation_cache',
]);
}
// assign 分配变量给到模板
public function assign($var, $value = null)
{
if (is_array($var)) {
$this->data = array_merge($this->data, $var);
} else {
$this->data[$var] = $value;
}
}
public function display($template)
{
echo $this->twig->render($template . ".html", $this->data);
}
//成功之后
function success($url, $msg)
{
echo "";
}
//失败之后
function error($url, $msg)
{
echo "";
}
}
class Test extends BaseController
{
function index()
{
$this->assign("title", "@@@@@@@@");
$this->assign("one", "abc");
$this->assign("two", "ttt");
$this->assign("alist", array("aa" => "bb", "ccc" => "3333", "ddd", "wwwww"));
//dd($this->data);
$this->display('index');
}
}
模板中调用如下即可. 至于循环等,看文档中介绍.
<title> {{ title }}</title>
<ul id="navigation">
{% for item in alist %}
<li>{{item}}</li>
{% endfor %}
</ul>
composer require catfan/medoo
{
"require": {
"monolog/monolog": "2.1.1",
"noahbuscher/macaw": "dev-master",
"twig/twig": "^3.1",
"catfan/medoo": "^1.7"
},
"autoload": {
"psr-4": {
"controllers\\": "app/controllers/",
"models\\": "app/models/"
},
"files": [
"app/helpers.php"
]
}
}
namespace models;
use Medoo\Medoo;
class BaseDao extends Medoo
{
function __construct()
{
$options = [
'database_type' => 'mysql',
'database_name' => 'lmonkey',
'server' => 'localhost',
'username' => 'root',
'password' => 'root',
'prefix' => 'ew_',
];
parent::__construct($options);
}
}
namespace models;
class User extends BaseDao
{
}
$data = $user->select("user", "*");
$this->assign("userlist", $data);
上述,框架的几大部分都结束了. 如果此时代码给到其他人,需要在项目目录下,命令行输入命令 composer install 来安装一下.
create table ew_category(
id int(10) not null auto_increment,
catname varchar(30) not null,
pid decimal(10, 0) not null,
ord decimal(10, 0) not null,
primary key(`id`)
) default charset = utf8mb4;
insert into ew_category values(1, "one", "0", "3");
insert into ew_category values(2, "two", "0", "0");
insert into ew_category values(3, "three", "0", "0");
insert into ew_category values(4, "four", "0", "0");
insert into ew_category values(5, "a111", "1", "3");
insert into ew_category values(6, "b111", "1", "0");
insert into ew_category values(7, "a222", "2", "0");
insert into ew_category values(8, "b222", "2", "0");
insert into ew_category values(9, "aaaaa", "5", "3");
insert into ew_category values(10, "bbbbb", "5", "0");
insert into ew_category values(11, "xxxxxx", "7", "0");
insert into ew_category values(12, "yyyyyy", "7", "0");
// 分类管理
Macaw::get("/catelist", "controllers\\Category@index");
// 图书管理
Macaw::get("/booklist", "controllers\\Book@index");
require(“class/cattree.php”);
use lmonkey\CatTree as CT;
class Category extends BaseController
{
public function index()
{
$db = new BaseDao();
$treelist = $db->select("category", ["id", "catename", "pid", "ord"]);
//$ntree = CT::getTree($treelist);
$ntree = CT::getList($treelist);
$this->assign("treeList", $ntree);
$this->display("category/index");
}
}
{% for item in treeList %}
<tr>
<td><input type="text" size="2" value="{{item.ord}}"></td>
<td>
{% for i in 0..item.level*8 %}
{% endfor %}
|-{{item.catename}}</td>
<td>修改/删除</td>
</tr>
{% endfor %}
显示的演示如下:
Macaw::get("/category/toadd", “controllers\Category@toadd”);
namespace controllers;
use lmonkey\CatTree as CT;
use models\BaseDao;
class Category extends BaseController
{
public function index()
{
$db = new BaseDao();
$treelist = $db->select("category", ["id", "catename", "pid", "ord"]);
//$ntree = CT::getTree($treelist);
$ntree = CT::getList($treelist);
$this->assign("treeList", $ntree);
$this->display("category/index");
}
//排序方法
public function order()
{
$db = new BaseDao();
foreach ($_POST["id"] as $key => $value) {
$db->update("category", ['ord' => $value], ["id" => $key]);
}
$this->success("/catelist", "排序成功!");
}
//添加方法展示
public function toadd()
{
$db = new BaseDao();
$treelist = $db->select("category", ["id", "catename", "pid", "ord"]);
$ntree = CT::getList($treelist);
$this->assign("treeList", $ntree);
$this->display("category/toadd");
}
//添加方法post添加
public function doadd()
{
$db = new BaseDao();
unset($_POST['submit']);
$data = $db->insert("category", $_POST);
if ($data->rowCount() > 0) {
$this->success("/catelist", "添加成功!");
}else{
$this->error("/category/toadd", "添加失败!");
}
}
}
部分源码, 主要是 流程的上的,避免逻辑错误.
//修改方法展示
public function toupdate()
{
$db = new BaseDao();
$treelist = $db->select("category", ["id", "catename", "pid", "ord"]);
$ntree = CT::getList($treelist);
$this->assign("treeList", $ntree);
//获取一条要修改的记录
$cate = $db->get("category", ["id", "catename", "pid", "ord"], ["id" => $_GET['id']]);
$this->assign("cate", $cate);
$this->display("category/toupdate");
}
//修改方法
public function doupdate()
{
$db = new BaseDao();
unset($_POST['submit']);
$id = $_POST["id"];
unset($_POST["id"]);
$treelist = $db->select("category", ["id", "catename", "pid", "ord"]);
$ntree = CT::getList($treelist);
$selftree = $ntree[$id];
if (in_array($_POST["pid"], explode(",", $selftree["childs"]))) {
$this->error("/catelist", "不能将分类修改到自己的子类下面!");
} else {
$data = $db->update("category", $_POST, ["id" => $id]);
if ($data->rowCount() > 0) {
$this->success("/catelist", "修改成功!");
} else {
$this->error("/catelist", "修改失败!");
}
}
}
// 删除
public function dodelete()
{
$db = new BaseDao();
$treelist = $db->select("category", ["id", "catename", "pid", "ord"]);
$ntree = CT::getList($treelist);
$selftree = $ntree[$_GET["id"]];
if (!empty($selftree["childs"])) {
$this->error("/catelist", "只能删除空文分类!");
} else {
$data = $db->delete("category", ["id" => $_GET["id"]]);
if ($data->rowCount() > 0) {
$this->success("/catelist", "删除成功!");
} else {
$this->error("/catelist", "删除失败!");
}
}
}
参考代码如下:
//添加方法post添加
public function doadd()
{
$db = new BaseDao();
unset($_POST['submit']);
//上传路径
$path = dirname(dirname(__DIR__)) . "/uploads";
// 文件上传
$builder = new UploadHandlerBuilder(); //create a builder.
$handler = $builder
->allowExtensions(['jpg', 'png', 'gif'])
->allowMimeTypes(['image/*', 'text/plain'])
->saveTo($path) //save to local
->getHandler();
$files = $handler->handle();
$filename = $files['filename']->getUploadedFile()->getClientOriginalName();
// 图片处理的包(大小,尺寸,水印)
$img = Image::make($path . '/' . $filename);
$img->resize(150, 240);
// insert a watermark, 加水印
$img->insert($path . '/watermark.png');
// save image in desired format
$img->save($path . '/pre_' . $filename);
$_POST["filename"] = $filename;
$data = $db->insert("book", $_POST);
if ($data->rowCount() > 0) {
$this->success("/booklist", "添加成功!");
} else {
$this->error("/book/toadd", "添加失败!");
}
}
public function index($num = 1)
{
$db = new BaseDao();
$treelist = $db->select("category", ["id", "catename", "pid", "ord"]);
//$ntree = CT::getTree($treelist);
$ntree = CT::getList($treelist);
//分页
$totalItems = $db->count("book");
$itemsPerPage = 5;
$currentPage = $num;
$urlPattern = '/booklist/(:num)';
$start = ($currentPage - 1) * $itemsPerPage;
$books = $db->select("book", "*", ["LIMIT" => [$start, $itemsPerPage]]);
$this->assign("books", $books);
$paginator = new Paginator($totalItems, $itemsPerPage, $currentPage, $urlPattern);
$this->assign("fpage", $paginator);
$this->assign("treeList", $ntree);
$this->display("book/index");
}
composer 是一个非常好的php包管理工具, 将一些功能化的操作放到包中. 用的时候, composer拿下来用.
大概步骤:
后期,自己会记录创建一个属于自己的 composer包.