读书频道 > 网站 > 网页设计 > PHP编程实战
1.5 接口、迭代器和抽象类
14-10-31    奋斗的小年轻
收藏    我要投稿   

本文所属图书 > PHP编程实战

本书主要内容包括:PHP 5 3 面向对象编程、PHP 的一些新特性、如何编写基于SQL 和NoSQL 的数据库交互程序、如何使用流行的PHP 相关工具、如何编写社交媒体应用程序,并介绍了NoSQL 数据存储以及为云生态编立即去当当网订购
 
在面向对象的世界里,对象的另一个经典类型是接口。接口是一个描述一整套方法的对象,某类可能选择其中的方法去实现。接口如下所示。
interface interf { 
  public function f1($x,$y,...,); 
  public function f2(....); 
  …. 
  public function fn(...); 
}
 
请注意,上述代码没有方法代码的规范说明,仅有参数的名称和数量。一个类可以选择实现这样的接口,如下所示。
class c extends parent implements interf { 
(all functions listed in the interface must now be defined) 
… 
)
 
接口可以从其他接口继承而来,就像类一样。语法也是相同的。
interface interf2 extends interf1 { 
   function f1(...); 
}
 
新的接口interf2将包含来自接口interf1的所有函数,加上新的函数,均由interf2定义。代码清单1-9是一个例子。
 
代码清单1-9 新接口interf2的例子
<?php  
interface i1 {  
    public function f1($a);  
}    
interface i2 extends i1 {  
    public function f2($a);  
}  
class c1 implements i2 {  
    private $memb;  
    function __construct($memb) {  
        $this->memb = $memb;  
    }  
    function f2($x) {  
        printf("Calling F2 on %s with arg: %s\n", $this->memb, $x);  
    }  
$x = new c1("test");  
$x->f2('a');
 
当执行这个脚本时,就会产生一个错误,因为接口i1的函数f1没有定义。错误的输出如下。
Fatal error: Class c1 contains 1 abstract method and must therefore be declared abstract or
implement the remaining methods (i1::f1) in /home/mgogala/work/book/script2.6.php on line 17
 
接口是Java编程中的标准结构,与PHP等脚本语言有稍许不同。下面将要看到的例子是关于接口Iterator的,它是PHP语言不可或缺的组成部分。迭代器是实现PHP内部接口(Iterator)的类的对象。定义接口Iterator如下所示。
interface Iterator {
    public function rewind();       // 将迭代器倒回到第一个元素
    public function next();         // 向前移到下一个元素
    public function key();          // 返回当前元素的键
    public function current();      // 返回当前的元素
    public function valid();        // 检查当前位置是否有效
}
 
实现接口Iterator的任何类都可以在for循环中使用,它们的对象被称为迭代器(iterator)。如代码清单1-10所示。
 
代码清单1-10 实现接口Iterator的任何类都可以在for循环中使用
<?php 
class iter implements iterator { 
    private $items; 
    private $index = 0; 
    function __construct(array $items) { 
        $this->items = $items; 
    } 
    function rewind() { 
        $this->index = 0; 
    } 
    function current() { 
        return ($this->items[$this->index]); 
    } 
    function key() { 
        return ($this->index); 
    } 
    function next() { 
        $this->index++; 
        if (isset($this->items[$this->index])) { 
            return ($this->items[$this->index]); 
        } else { 
            return (NULL); 
        } 
    } 
    function valid() { 
        return (isset($this->items[$this->index]));
    } 
$x = new iter(range('A', 'D')); 
foreach ($x as $key => $val) { 
    print "key=$key\tvalue=$val\n"; 
 
这个关于PHP迭代器的例子,尽管非常典型,但其实很简单。执行时,这个脚本就会生成下面的输出。
key=0   value=A  
key=1   value=B  
key=2   value=C  
key=3   value=D
 
脚本的主要组成部分,即整个练习的原因所在,是位于脚本最下面的循环。此语法也经常为数组使用,但$x不是一个数组,它是类iter的一个对象。迭代器是可以像数组一样表现的对象。这是通过实施接口Iterator实现的。这在什么情况下是适用的呢?文件里的行或由游标返回的行可以很轻松地迭代通过。请注意,我们仍然不能使用表达式$x[$index];计数变量只是用于顺序遍历数组。通过实现Iterator接口完成的话,将会是一个相当繁琐的练习,就如代码清单1-11。
 
代码清单1-11 实现接口Iterator
<?php 
class file_iter implements iterator { 
    private $fp; 
    private $index = 0; 
    private $line; 
    function __construct($name) { 
        $fp = fopen($name, "r"); 
        if (!$fp) { 
            die("Cannot open $name for reading.\n"); 
        } 
        $this->fp = $fp; 
        $this->line = rtrim(fgets($this->fp), "\n"); 
    } 
    function rewind() { 
        $this->index = 0; 
        rewind($this->fp); 
        $this->line = rtrim(fgets($this->fp), "\n"); 
    } 
    function current() { 
        return ($this->line); 
    } 
    function key() { 
        return ($this->index); 
    } 
    function next() { 
        $this->index++; 
        $this->line = rtrim(fgets($this->fp), "\n"); 
        if (!feof($this->fp)) { 
            return ($this->line); 
        } else { 
            return (NULL); 
        } 
    } 
    function valid() { 
        return (feof($this->fp) ? FALSE : TRUE); 
    } 
$x = new file_iter("qbf.txt"); 
foreach ($x as $lineno => $val) { 
    print "$lineno:\t$val\n"; 
 
qbf.txt文件是一个小的文本文件,包含著名的全字母短句(pangram),即该谚语包含所有26个英文字母。
quick brown fox  
jumps over  
the lazy dog  
 
这个脚本会读取文件,并在屏幕上打印出来,每行前面是行号。它使用标准文件进行操作,如fopen、fgets和rewind。rewind函数不仅仅是迭代器接口里的一个方法名称,它还是一个操纵文件的核心函数,修改文件处理,指向文件的开头。
 
行号从0开始,目的在于使文件尽可能类似于数组。到目前为止,我们已经见过成为迭代器的文件和数组。具有“get next”和“am I done”方法的任何类型的实体可以用一个迭代结构代表,并循环遍历。数据库游标就是这样一个例子。它有“get next”方法,称为“fetch”;同时,利用handle status,它还能够告知何时取回最后一条记录。对数据库游标实现迭代器类的操作与代码清单1-11中对文件所做的操作非常类似。file_iter类只是一个例子。PHP 5包含了一套命名为标准PHP库(SPL)的内部类,类似于C++著名的STL。SPL的SplFileObject类更为详尽,并且它的确实现了迭代器类。我们的整个脚本可以写得更简单,就像下面这样。
<?php  
$x = new SplFileObject("qbf.txt","r");  
foreach ($x as $lineno => $val) {  
    if (!empty($val)) {print "$lineno:\t$val"; } 
?> 
 
请注意,新行字符不再从该行剥离。我们必须测试该行为空行。如果我们忽视测试空行,SplFileObject类将推进文件结束。然而,它仍然是一个使工作变得更轻松的类。唯一一个真正有用的函数是SplFileClass缺失的fputcsv,该函数输出CSV格式的数组,而且很容易编写。
 
在SPL还有其他有用的类和接口。有关SPL的内容超出了本书的范围,有兴趣的读者可以在以下网站查找相关信息:www.php.net/manual/en/book.spl.php。
 
也有一套实现了数据库的游标和查询的迭代器的类的标准。这套类被称为ADOdb,它使程序员就像通过一个文件或一个数组,使用foreach循环遍历查询结果。ADOdb类集将在后续章节更详细地介绍。
 
抽象类和接口之间的区别是什么?两者均被用作模板,其他类从而可以继承或实现它们。但抽象类更严格,结构定义也更为严格。除了抽象方法,抽象类可以有真正的成员和方法,甚至是final方法,不能重载,只能那么用。 
点击复制链接 与好友分享!回本站首页
分享到: 更多
您对本文章有什么意见或着疑问吗?请到论坛讨论您的关注和建议是我们前行的参考和动力  
上一篇:1.3 功能
下一篇:1.5 小结
相关文章
图文推荐
JavaScript网页动画设
1.9 响应式
1.8 登陆页式
1.7 主题式
排行
热门
文章
下载
读书

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训
版权所有: 红黑联盟--致力于做最好的IT技术学习网站