PHP 5:接口抽象类与适配模式

 
PHP 5 :接口抽象类与适配模式
 
 
         相对于PHP 4,PHP 5在面向对象编程(OOP)模式方面作出了巨大的改进,使它看起来更加像Visual Basic .NET和Java,PHP 5中改进的对象模式加上OOP,现在开发起程序来更加容易,并且也给予了程序员更大的灵活性。
         在本文中,将介绍PHP 5对象模式的一些新特性,也会提及怎样创建一个类似于Pear DB的数据库抽象层,并且还将进一步讲解如何修改此抽象层以作他用。
 
 
         简介
         PHP其中一个最擅长的领域,是在于对数据库连接的支持,它可以连接并与任何你能想像到的数据库服务器或接口进行通讯;然而,这也带来了一些与生俱来的问题,每种数据库都有其自身的特性与功能,并且,大多数都有各自的SQL版本。尽管访问这些数据库的函数彼此类似,但还是存在一些细小差别,当你要把一个为MySql编写的应用程序移植到MS SQL服务器上来时,将要把所有对mysql_query()的调用,手工调整为mssqp_query()。
         虽然我们不至于开发一个独立于数据库的SQL版本,但PHP 5中的新特性已可用于构建一套一致的数据库API,并且对存储过程也提供了支持,这样就不会在从一种数据库系统切换到另一种数据库系统时,痛苦得要一行一行修改代码了。
 
 
         接口抽象类与适配模式
         下面将要介绍PHP 5的第一个新特性是抽象类与接口,这些概念只不过是面向对象编程的一些东西,将有助于程序员遵循良好的编码标准。
 
 
         抽象类
         抽象类是一种只由程序员实现了一部分的类,它可以包含一个或多个的抽象方法,一个抽象方法仅仅是一个函数定义,只是告诉程序员此方法必须要在子类中实现。
         要创建一个抽象类,可如例1所示:
 
例1:一个抽象PHP类
 
<?php 
abstract class Weapon 
    private $SerialNumber; 
    abstract public function fire(); 
 
 
    public function __construct($SerialNumber) 
    { 
        $this->SerialNumber = $SerialNumber; 
    }
 
    public function getSerialNumber() 
    { 
        return $this->SerialNumber; 
    } 
?>
 
         例1中的抽象类Weapon(武器)包含了某些方法,但其中未实现fire()(开火)方法,是因为不同的“武器”,“开火”方法也不同,在此处声明为abstract,意味着将在一个更详细的子类中实现。
         因为类是抽象的,所以不能创建一个实例(因为它只实现了一部分),而后的子类必须通过继承创建,并实现其自己的fire(开火)方法。例2演示了一个自抽象Weapon类创建的子类:
 
例2:扩展抽象Weapon类
 
<?php 
class Gun extends Weapon 
    public function fire() 
    { 
        if($this->SafetyOff) { 
            return $this->CurrentBullet; 
        } 
    } 
 
 
class Cannon extends Weapon 
    public function fire() 
    { 
        $this->NeedsLoading = true; 
        return $this->CurrentCanon; 
    } 
?>
 
         现在可以创建Cannon与Gun类的一个实例了,因为它们已是一个完全实现的Weapon类的子类。
 
 
         接口
         接口与抽象类非常类似,实际上接口使用了和类与抽象类相同的命名空间,正因为此,所以你不能定义一个与某个类同名的接口。接口是一个完全抽象的类,除了可对它进行子类化之外,它未实现任何方法。
         接口可用于创建数据库抽象层,以确保每次在为特定数据库创建一个类时,都有相同的API。因为PHP程序员通常会使用MySql,所以在此我们以MySql的函数作为示例,以下是经常使用的MySql函数列表:
 
mysql_connect()
mysql_error()
mysql_errno()
mysql_query()
mysql_fetch_array()
mysql_fetch_row()
mysql_fetch_assoc()
mysql_fetch_object()
mysql_num_rows()
mysql_close()
 
         如果你创建的所有数据库类API,都使用相同的方法,并且有相同的返回类型,那么可以保证,在从一种数据库切换到另一种数据库时,如MySql到Postgre SQL,将是毫无困难的。请看例3:
 
例3:一个抽象数据库接口
 
interface DB
{
    public function connect();
    public function error();
    public function errno();
    public static function escape_string($string);
    public function query($query);
    public function fetch_array($result);
    public function fetch_row($result);
    public function fetch_assoc($result);
    public function fetch_object($result);
    public function num_rows($result);
    public function close();
}
 
         任何实现此接口的类,必须定义在其中声明的每一个方法,且每个方法至少都具有它们接口定义中的相应参数,如果有需要,参数可以更多些,但不能更少。
 
 
         适配模式
         来看一下例4中实现了数据库接口的类,这是关于适配模式的一个范例,程序员通常是为了顺应某个API而使用适配模式,而这个API可能是出于另一个面向对象的API,或者是在此处没有完成的API,或者改编自某个模块化API。
         请注意escape_string()方法是怎样被作为一个静态方法包含进来的,这个方法并不需要一个数据库的活动连接,也不需要任何实现了此DB接口对象的实例。根据个人观点,这是任何数据库实现中,最重要的一个方法,如果实现得不好,将会使你的程序易受SQL注入攻击。
 
例4:实现数据库接口
 
class MySqlDB implements DB
    {
        private $link;
 
        public function connect($server='', $username='', $password='', $new_link=true, $client_flags=0)
        {
            $this->link = mysql_connect($server, $username, $password, $new_link, $client_flags);
        }
 
        public function errno()
        {
            return mysql_errno($this->link);
        }
 
        public function error()
        {
            return mysql_error($this->link);
        }
 
        public static function escape_string($string)
        {
            return mysql_real_escape_string($string);
        }
 
        public function query($query)
        {
            return mysql_query($query, $this->link);
        }
 
        public function fetch_array($result, $array_type = MYSQL_BOTH)
        {
            return mysql_fetch_array($result, $array_type);
        }
 
        public function fetch_row($result)
        {
            return mysql_fetch_row($result);
        }
 
        public function fetch_assoc($result)
        {
            return mysql_fetch_assoc($result);
        }
 
        public function fetch_object($result)
        {
            return mysql_fetch_object($result);
        }
 
        public function num_rows($result)
        {
            return mysql_num_rows($result);
        }
 
        public function close()
         {
            return mysql_close($this->link);
        }
 
         你可能已经注意到了,此处较多地使用了mysql函数,而不是修改自例3中接口的方法,不管怎样,这些函数,足够满足大多数普通数据存储及检索程序的需要了。请看例5:
 
例5:创建一个数据库类
 
$db = new MySqlDb;
    $db->connect('host', 'username', 'password');
    $db->query('use users'); //在此我们也可以使用$db->select_db,但它与接口不一致。
 
    $result = $db->query("SELECT username FROM users");
 
    while($row = $db->fetch_assoc($reuslt)) {
        echo($row['username']);
    }
 
         如例5中所示,你现在可以为每一个数据库创建一个类,只要它实现了DB接口,在从一种数据库切换到另一种数据库时,只需修改一行代码:
 
$db = new MsSqlDb;
 
 
         结论
         在本文中,初步讨论了怎样创建一个访问数据库的抽象层,并据此创建一个有助于隔离程序的接口,以在将来方便地从一种数据库切换到另一种数据库,而不用重写整个程序。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值