组件化开发与composer

composer

组件安装

自动加载

PSR-0和PSR-4标准

1
2
3
4
5
6
7
{
"autoload":{
"psr-4":{"APP\\":"app/"
"BPP\\":"bpp/"
}
}
}

文件包含

include和require关键字

include和require关键字用于包含并运行指定文件。两者作用几乎一样,只是处理失败的方式不同,require在出错时会导致脚本程序运行终止,而include只是发出警告,而脚本程序会继续运行。

类的自动加载

类的自动加载可以通过魔术方法__autoload(string $class)实现,也可以通过函数spl_autoload_register注册一个自动加载方法,相应实例如下:

1
2
3
4
function __autoload($class)
{
require_once($class.".php");
}

当使用一个类名时,如果该类没有被当前文件包含,则会自动调用————autoload魔术方法。但在实际应用中,通常使用spl_autoload_register注册自动以德函数作为自动加载类的实现,因为__autoload()魔法函数只可以定义一次,而spl_autoload_register可以将多个类自动加载方法注册到队列。

在Laravel框架中,通过函数spl_autoload_register()实现类自动加载函数的注册,其中
类的自动加载函数队列中包含了两个类的自动加载函数,一个是composer生成的基于PSR
规范的自动加载函数,另一个是Laravel框架核心别名的自动加载函数。下面将给出Laravel
框架中的部分代码,进而介绍该框架下类的自动加载过程。这里Laravel框架所在根目录为
“laravel”,其中composer生成的自动加载函数注册过程如下:

文件:laravel\public\index.php

1
2
3
<?php
require __DIR__.*/../bootstrap/autoload.php;
laravel\bootstrap\autoload.php

文件: laravel\bootstrap\autoload.php

1
2
3
<?php 
define (' LARAVEL_START', microtime (true));
require __DIR__.'/・・/vendor/autoload.php1;

在Laravel框架中,public\index.php文件为请求的入口文件,其中第一句便是包含启
动文件夹下的自动加载的文件,而该文件继续包含vendor目录下的自动加载文件,其中
vendor目录是composer生成的依赖包目录,而内部的自动加载文件也是composer生成的,
用于自动加载依赖包中的所有文件。下面简单介绍composer生成的类自动加载函数是如何
实现的。

文件:laravel\vendor\autoload.php

1
2
3
<?php 
require_once __DIR__ . '/composer' . '/autoload_real.php';
return ComposerAutoloaderInit99123d508294c719fdcf537b9ee84731 ::getLoader();

文件:laralvel\vendor\composer\ autoload_real.php

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?php 
class ComposerAutoloaderInit99123d508294c719fdcf537b9ee84731
{
private static $loader;
public static function loadClassLoader($class)
{
if (*Composer\Autoload\ClassLoader === $class)
{
require __DIR__ .'/ClassLoader.php';
}
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInit99123d508294c719fdcf53
7b9ee84731'z 'loadClassLoaderr), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInit99123d508294c719fdef
537b9ee84731', 'loadClassLoader1));
$map = require __DIR__ . */autoload_namespaces.phpr;
foreach ($map as $namespace => $path) {
$loader->set($namespacer $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespacer $path);
}
$classMap = require __DIR__ ・•/autoload_classmap.php1;
if ($classMap) {
$loader->addClassMap($classMap);
}
$loader->register(true) ; //注册类自动加载函数
$includeFiles = require __DIR__ .'/autoload_files.php';
foreach ($includeFiles as $file) {
composerRequire99123d508294c719fdcf537b9ee84731($file);
}
return $loader;
}
}
function composerRequire99123d508294c719fdcf537b9ee84731($file){
require $file;
}
}

(后面太多了不想拷贝了)

Laravel框架中的设计模式

服务容器

依赖和耦合

工厂模式

IOC模式

IoC (Inversion of Control)模式又称依赖注入
(Depe-ndency Injection )模式。控制反转是将组件间的依赖关系从程序内部提到外部容器
来管理,而依赖注入是指组件的依赖通过外部以参数或其他形式注入,两种说法其实本质上
是一个意思。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Traverller
{
protected $trafficTool;
public function __construct(Visit $trafficTool)
{
$this->trafficTool=$trafficTool;
}
public function vistTibet()
{
$this->trafficTool->go();
}
}

//生成以来的交通工具实例

$trafficTool = new Leg();
//依赖注入的方式解决依赖问题

$tra=new Traveller($trafficTool);
$tra->visitTibet();

请求处理管道

上面已经解决了 Laravel框架中一个关键技术,就是利用服务容器和服务提供者解决依
赖注入及资源获取的功能,有了它就可以随时获取需要的服务,实现想要的功能。但对于服
务器来说,真正要实现的功能是处理输入的请求,并将生成的响应输出给客户端,而在处
理请求的过程中需要经历很多处理步骤,这些步骤需要做到松耦合,可以随时在这些步骤
中间添加新的处理功能而使改动尽可能小,通过源码的注解,设计者将其比喻成“洋葱”,
像它一样分很多层,每一层具有一定的功能,可以随时添加或修改这些层,而官方文档中将
这些层称为中间件,通过这些中间件使得程序的可扩展性大大增强。这里,其实使用的是一
种装饰者模式,只是PHP特有的编程方式使得其形式发生变化,下面我们就逐步揭开它的
面纱。

装饰者模式

装饰者模式是在开放一关闭原则下实现动态添加或减少功能的一种方式。以Laravel框
架为例,在解析请求生成响应之前或之后需要经过中间件的处理,主要包括验证维护模式、
Cookie加密、开启会话、CSRF保护等,而这些处理有些是在生成响应之前,有些是在生成
响应之后,在实际开发过程中有可能还需要添加新的处理功能,如果在不修改原有类的基础
上动态地添加或减少处理功能将使框架可扩展性大大增强,而这种需求正好可以被装饰者模
式解决。

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<?php
interface Decorator
{
public function display();
}
class XiaoFang implements Decorator
{
private $name;
public function __construct($name)
{
$this->name = $name;
}
public function display()
{
echo "我是". $this->name ."我出门了! ! ! " . "<br>";
}
}
class Finery implements Decorator
{
private $component;
public function __construct(Decorator $component)
{
$this->component = $component;
}
public function display()
{
$this->component->display();
}

class Shoes extends Finery
{
public function display()
{
echo "穿上鞋子"."<br>";
parent::display();
}
}

class Skirt extends Finery
{
public function display()
{
echo ”穿上裙子 n. r<br>*;
parent::display();
}
}
class Fire extends Finery
{
public function display()
{
echo'出门前先整理头发'.'<br>';
parent::display();
echo '出门后再整理一下头发' . '<br>';
}
}
$xiaofang = new XiaoFang (1 小芳 1);
$shoes = new Shoes($xiaofang);
$skirt = new Skirt($shoes);
$fire = new Fire ($skirt);
$fire->display ();
输出:
岀门前先整理头发
穿上裙子
穿上鞋子
我是小芳,我出门了
出门后再整理一下头发

我们假设小芳接到一个电话算是请求,而小芳出门是对请求的响应,那么在小芳出门
前后要对自己进行打扮,对应于Laravel框架中,这些打扮的步骤就相当于中间件的功能,
而小芳出门是对请求的真正响应。在小芳打扮的过程中,可以随时增加新的打扮类,只要该
类继承Finery类(装饰类)并调用父类的同名方法,就可以在实现时重新组织打扮过程,实
现打扮步骤的增加或减少,例如加一件衣服、化个妆等。这就是装饰者模式的应用场景。

上面的输岀内容是Laravel框架对请求处理的部分流程,这里面大部分与上一节中装饰
者模式形式相似,但通过回调函数生成整个处理流程的过程还是比较难以理解。这里给一个
简单的实例用于理解,代码如下:

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
27
28
29
30
31
32
33
<?php
interface Step
{
public static function go(Closure $next);
}
class FirstStep implements Step
{
public static function go(Closure $next)
{
echo "开启 session,获取数据".'<br>';
$next ();
echo "保存数据,关闭 session".'<br>';
}
}
function goFun($step, $className)
{
return function () use($stepx $className)
{
return $className::go($step);
};
}
function then ()
{
$steps = [MFirstStepn];
$prepare = function () {echo "请求向路由器传递,返回响应";}
$go = array_reduce($steps, ngoFunH, $prepare);
$go();
}
then ();
输出:
开启session,获取数据
请求向路由器传递,返回响应
保存数据,关闭session

请求到响应的生命周期