Frenlee

PHP接口的使用

PHP接口是什么?

接口是两个PHP对象之间的契约,其目的不是让一个对象依赖另一个对象的身份,而是依赖另一个对象的能力。接口把我们的代码和依赖解耦了,而且允许我们的代码依赖任何实现了预期结果的第三方代码。我们不管第三方代码时如何实现接口的,只关心第三方代码是否实现了指定的接口。

下面看一个实例

虚构一个名为DocumentStore的PHP类,这个类的作用是从不同的源收集文本:可以从远程URL读取HTML,可以读取流资源,也可以收集终端命令的输入。而且,Document实例中的每个文档都有唯一的表示符。

####资源仓库类

可以收集实现了Documentable接口类的信息

1
2
3
4
5
6
7
8
9
10
11
12
13
class DocumentStore{
protected $data = array();

public function addDocument(Documentable $document){
$key = $document->getId();
$value = $document->getContent();
$this->data[$key] = $value;
}

public function getDocuments(){
return $this->data;
}
}

在DocumentStore类中addDocument的参数只能是Documentable类的实例,那就需要定义一个Documentable的接口。这样就可以满足很多实现了这个接口的类作为addDocument的参数。

定义接口

定义了实现类需要实现的方法 统一实现标准

1
2
3
4
interface Documentable{
public function getId();
public function getContent();
}

这个接口的定义表明,实现Documentable接口的任意任何对象都必须提供一个公开的getId()方法和一个公开的getContent()方法。

实现接口的操作类

下面我们就可以来实现了该接口的操作类了,先实现一个使用curl从远程url获取html的类。

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
#html类  使用culr从url获取html
class HtmlDocument implements Documentable{

protected $url;

function __construct($url){
$this->url = $url;
}

public function getId(){
return $this->url;
}

public function getContent(){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_MAXREDIRS, 3);
$html = curl_exec($ch);
curl_close($ch);
return $html;
}
}

实现读取流资源的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#文件流 获取文件信息
class StreamDocument implements Documentable{
protected $resource;
protected $buffer;

function __construct($resource, $buffer = 4096){
$this->resource = $resource;
$this->buffer = $buffer;
}

public function getId(){
return 'resouce-'.(int)$this->resource;
}

public function getContent(){
$streamContent = '' ;
rewind($this->resource);
while( feof($this->resource) === false){
$streamContent .= fread($this->resource, $this->buffer);
}
return $streamContent;
}
}

实现获取终端命令结果的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#终端命令执行  获取终端结果
class CommandOutputDocument implements Documentable{

protected $commend;

function __construct($commend){
$this->commend = $commend;
}

public function getId(){
return $this->commend;
}

public function getContent(){
return exec($this->commend);
}
}

使用

这三个类都实现了Documentable接口中的方法,下面来看下他们的使用:

1
2
3
4
5
6
7
8
9
$documentStore = new DocumentStore();
$cmdDoc = new CommandOutputDocument('ls C:/');
$documentStore->addDocument($cmdDoc);
$html = new HtmlDocument('http://www.qq.com');
$documentStore->addDocument($html);
$stream = new StreamDocument(fopen('stream.txt','rb'));
$documentStore->addDocument($stream);

print_r($documentStore->getDocuments());

可以看到使用接口后降低了代码之间的耦合度,同时使代码更灵活。