PHP数据库操作面向对象的优点

我们都知道如何从Mysql获取我们需要的行(记录),读取数据,然后存取一些改动。很明显也很直接,在这个过程背后也没有什么拐弯抹角的。然而对于我们使用面对对象的程序设计(OOP)来管理我们数据库中的数据时,这个过程就需要大大改进一下了。这篇文章将对如何设计一个面对对象的方式来管理数据库的记录做一个简单的描述。你的数据当中的所有内部逻辑关系将被封装到一个非常条理的记录对象,这个对象能够提供专门(专一)的确认代码系统,转化以及数据处理。随着Zend Engine2 和PHP5的发布,PHP开发者将会拥有更强大的面对对象的工具来辅助工作,这将使这个过程(面对对象地管理数据库)更有吸引力。

以下列出了一些使用对象来描叙你的数据库的有利方面:

存取方法(Accessor methods)将会使你对属性的读取和写入过程做到完全的控制
每一级的每个记录和属性(的操作)都有确认过程
从关系表中智能的获取对象
重复使用的逻辑方法意味着所有的数据交互都要通过相同的基础代码(codebase),这将使维护变得更加简单
代码简单,因为不同的记录的内部逻辑都已经包含在各自所处的类(class)当中,而不是繁琐的库(lib)文件
在手工编写代码和SQL查询语句时,出错的机会将更少

存取方法(Accessor methods)

存取方式是通过类给实例(instance)的变量赋值。一个例子,我有一个叫User的类,并且有一个实例$username,我会写这样的存取方法(函数),User->username()和User->setUsername()用来返回和给实例赋值。

<?php
class User {
var $username;

function username() {
return $this->username;
}

function setUsername($newUsername) {
$this->username = $newUsername;
}
}
?>

这里有很好的理由让我们编写这样的“特别的代码”。它将使开发者更灵活的改变类的繁琐的工作,因为这一过程将不需要其他的使用类的php代码。让我们来看看下面这个更加完善的可信赖的User类。

变量$username将不复存在,所有的东西都被整合的放在数组$_data当中
如果username是空的话,username()函数将提供一个缺省(默认)的值给它
setUsername()过程将在接受值之前确认username是否合乎标准格式(如字长等)

<?php
class User {
var $_data = array(); // associative array containing all the attributes for the User

function username() {
return !empty($this->_data['username']) ? $this->_data['username'] : '(no name!)';
}

function setUsername($newUsername) {
if ($this->validateUsername($newUsername)) {
$this->_data['username'] = $newUsername;
}
}

function validateUsername(&$someName) {
if (strlen($someName) > 12) {
throw new Exception('Your username is too long'); // PHP5 only
}
return true;
}
}
?>

显而易见,这对我们控制存取对象的数据有很大帮助。如果一个程序员已经直接地存取username的信息,以上代码的变化将会破坏他的代码。然而我们可以使用(类的)存取方法,就像上面代码中注释的那样,添加一个验证的功能而不需要改变任何其他的东西。注意username的验证(例子当中是不能超过12字节)代码是独立在setUsername()方法之外的。从验证到存储到数据库的过程轻而易举。而且,这是个非常好的单凭经验的方法,一个方法或一个类需要做的越少,它的重复使用的机会将会越大。这在你开始写一个子类时更加明显,假如你需要一个子类,并且又要跳过(忽略)父类方法(行为)中的一些特殊的细节,如果(针对这个细节的)方法很小而又精细,(修改它)只是一瞬间的过程,而如果这个方法非常臃肿,针对多种目的,你可能将在复制子类中大量代码中郁闷而终。

比方说,假如Admin是User类的一个子类。我们对adamin的用户可能会有不同的,相对苛刻一些的密码验证方法。最好是跨过父类的验证方法和整个setUsername()方法(在子类中重写)。

更多关于存取器(Accessor)
下面是一些其他的例子来说明如何使存取器用的更有效果。很多时候我们可能要计算结果,而不是简单的返回数组中的静态数据。存取方法还能做的一个有用的事情就是更新(updating)缓存中的值。当所有的变动(对数据的所有操作)都要通过setX()方法的时候,这正是我们根据X来重置缓存中的值的时刻。

于是我们的这个类层次变得更加明了:

内部变量$_data的处理被替换成受保护的私有方法(private methods)_getData()和_setData()
这类方法被转移到被称作记录(Record)的抽象的超级类(super class),当然它是User类下的子类
这个记录类(Record class)掌握所有存取数组$_data的细节,在内容被修改之前调用验证的方法,以及将变更的通知发给记录(Records),就像发给中心对象存储(ObjectStore)实例。

<?php
class User extends Record {

// --- OMITTED CODE --- //

/**
* Do not show the actual password for the user, only some asterixes with the same strlen as the password value.
*/
function password() {
$passLength = strlen($this->_getData('password'));
return str_repeat('*', $passLength);
}
/**
* Setting the user password is not affected.
*/
function setPassword($newPassword) {
$this->_setData('password', $newPassword);
}

/**
* fullName is a derived attribute from firstName and lastName
* and does not need to be stored as a variable.
* It is therefore read-only, and has no 'setFullname()' accessor method.
*/
function fullName() {
return $this->firstName() . " " . $this->lastName();
}

/**
* Spending limit returns the currency value of the user's spending limit.
* This value is stored as an INT in the database, eliminating the need
* for more expensive DECIMAL or DOUBLE column types.
*/
function spendingLimit() {
return $this->_getData('spendingLimit') / 100;
}

/**
* The set accessor multiplies the currency value by 100, so it can be stored in the database again
* as an INT value.
*/
function setSpendingLimit($newSpendLimit) {
$this->_setData('spendingLimit', $newSpendLimit * 100);
}

/**
* The validateSpendingLimit is not called in this class, but is called automatically by the _setData() method
* in the Record superclass, which in turn is called by the setSpendingLimit() method.
*/
function validateSpendingLimit(&$someLimit) {
if (is_numeric($someLimit) AND $someLimit >= 0) {
return true;
} else {
throw new Exception("Spending limit must be a non-negative integer"); //PHP5 only
}
}
}

/**
* Record is the superclass for all database objects.
*/
abstract class Record {
var $_data = array();
var $_modifiedKeys = array(); // keeps track of which fields have changed since record was created/fetched

/**
* Returns an element from the $_data associative array.
*/
function _getData($attributeName) {
return $this->_data[$attributeName];
}

/**
* If the supplied value passes validation, this
* sets the value in the $_data associative array.
*/
function _setData($attributeName, $value) {
if ($this->validateAttribute($attributeName, $value)) {
if ($value != $this->_data[$attributeName]) {
$this->_data[$attributeName] = $value;
$this->_modifiedKeys[] = $attributeName;
$this->didChange();
} else {
// the new value is identical to the current one
// no change necessary
}
}
}

/**
* For an attribute named "foo", this looks for a method named "validateFoo()"
* and calls it if it exists. Otherwise this returns true (meaning validation passed).
*/
function validateAttribute($attributeName, &$value) {
$methodName = 'validate' . $attributeName;
if (method_exists($this, $methodName)) {
return $this->$methodName($value);
} else {
return true;
}
}

function didChange() {
// notify the objectStore that this record changed
}
}
?>

现在我们拥有了一个抽象的超级类(Record),我们可以将User类里面大量的代码转移出来,而让这个User的子类来关注User的特殊项目如存取和验证方法。你可能已经注意到在我们的这个纪录类(Record class)没有任何的SQL代码。这并不是疏忽或者遗漏!对象存储类(ObjectStore class)(隐藏在第二部分)将负责所有和数据库的交互,还有我们的超级类Record的实例化。这样使我们的Record类更加瘦小而又有效率,而这对于评价我们处理大量对象的效率的时候是个重要因素。

(0)

相关推荐

  • PHP面向对象三大特点学习(充分理解抽象、封装、继承、多态)

    面象对向的三大特点:封装性.继承性.多态性 首先简单理解一下抽象:我们在前面定义一个类的时候,实际上就是把一类事物共有的属性和行为提取出来,形成一个物理模型(模版),这种研究问题的方法称为抽象一.封装性 封装就是把抽取出来的数据和对数据的操作封装在一起,数据被保护在内部,程序的其他部分只有被授权的操作(方法)才能对数据进行操作. php提供了三种访问控制修饰符 public 表示全局,本类内部,类外部,子类都可以访问 protected 表示受保护的,只有本类或子类可以访问 private 表示

  • PHP对象链式操作实现原理分析

    本文实例讲述了PHP对象链式操作实现原理.分享给大家供大家参考,具体如下: 什么是链式操作呢?使用jQuery的同学印象应该会很深刻.在jQuery中,我们经常会这样的来操作DOM元素: $("p").css("color").addClass("selected"); 连贯操作看起来的确很酷,也非常的方便代码的阅读.那么在PHP里面是否可以实现呢?答案是肯定的,当然了必须是在OOP中用才行,在过程化的程序中,就没有必要用这种方法了. 在PHP中

  • PHP实现链式操作的原理详解

    在一个类中有多个方法,当你实例化这个类,并调用方法时只能一个一个调用,类似: db.php <?php class db { public function where() { //code here } public function order() { //code here } public function limit() { //code here } } index.php <?php $db = new db(); $db->where(); $db->order()

  • php基础知识:类与对象(4) 范围解析操作符(::)

    范围解析操作符(也可称作 Paamayim Nekudotayim)或者更简单地说是一对冒号,可以用于访问静态成员.方法和常量,还可以用于访问被覆盖类中的成员和方法.  当在类的外部访问这些静态成员.方法和常量时,必须使用类的名字. 把 Paamayim Nekudotayim 在希伯莱文就是双冒号的意思. 在类的外部使用 :: 操作符 class MyClass {    const CONST_VALUE = 'A constant value'; } echo MyClass::CONST

  • PHP数据对象PDO操作技巧小结

    本文实例讲述了PHP数据对象PDO操作技巧.分享给大家供大家参考,具体如下: PHP 数据对象 (PDO) 扩展为PHP访问数据库定义了一个轻量级的一致接口. <?php try { $dsn = "mysql:host=localhost; port=3306; dbname=wsq_hotel; charset=utf-8"; $user = 'root'; $psw ='root'; $pdo = new PDO($dsn,$user,$psw); $sql = 'sele

  • php面向对象的方法重载两种版本比较

    多个函数用同一个名字,但参数表,即参数的个数或(和)数据类型可以不同,调用的时候,虽然方法名字相同,但根据参数表可以自动调用对应的函数. PHP4 中仅仅实现了面向对象的部分的.简单的功能,而 PHP5 以后对对象的支持就强大的多了. 对于多态的实现,PHP4 只支持覆盖(override),而不支持重载(overload).但我们可以通过一些技巧来"模拟"重载的实现. PHP5 虽然可以支持覆盖和重载,但重载在具体实现上,和其他语言还有较大的差别. 1,在 PHP4 中"模

  • PHP实现链式操作的核心思想

    PHP 链式操作的实现 复制代码 代码如下: $db->where()->limit()->order(); 在 Common 下创建 Database.php. 链式操作最核心的地方在于:在方法的最后 return $this; Database.php: <?php namespace Common; class Database{ function where($where){ return $this; //链式方法最核心的地方在于:在每一个方法之后 return $thi

  • php 面向对象的一个例子

    复制代码 代码如下: <?php class person{ //下面是人的成员属性 var $name; //人的名字 var $sex; //人的性别 var $age; //人的年龄 //定义一个构造方法参数为姓名$name,性别$sex和年龄$age function __construct($name,$sex,$age){ //通过构造方法传进来的$name给成员属性$this->name赋初始值 $this->name=$name; //通过构造方法传进来的$sex给成员属

  • PHP实现的连贯操作、链式操作实例

    PHP中的连贯操作看起来的确很酷,也非常的方便代码的阅读,当然了必须是在OOP中用才行,在过程化的程序中,就没有必要用这种方法了.有实现这个方法的有用_CALL来实现的,而我下面写的这个例子,则不是用_call的,大家可以扩展一下吧. 下面写的这个SQL语句组合类,主要是用于学习的,如果有同学想拿去用,请再完善一下. /* * SQL语句组合实例类,始发文章web开发笔记 * 学习用,非专业类 * */ class sql{ private $sql=array("from"=>

  • php面象对象数据库操作类实例

    本文实例讲述了php面象对象数据库操作类.分享给大家供大家参考. 具体实现代码如下: 复制代码 代码如下: //此处构造一个数据库操作类,封装所有数据库操作 //可以扩展便于后台管理程序的使用 Class MySQLDB  {     var $host;     var $user;     var $passwd;     var $database;    var $conn;       //利用构造函数实现变量初始化     //同时连接数据库操作    function MySQLD

  • PHP 面向对象 final类与final方法

    final---用于类.方法前. final类---不可被继承. final方法---不可被覆盖. final类不能被继承. 如果我们不希望一个类被继承,我们使用final来修饰这个类.这个类将无法被继承.比如我们设定的Math类,涉及了我们要做的数学计算方法,这些算法也没有必要修改,也没有必要被继承,我们把它设置成final类型. 复制代码 代码如下: <? //声明一个final类Math final class Math{ public static $pi = 3.14; public

随机推荐