面向对象程序设计的来源得自于人们看待电话、汽车这些物体的想法。很多程序设计者在讨论面向对象程序设计的时候喜欢用“包装”或者“继承”这些让一般人迷惑不解的词语。我们可以把面向对象这个概念和自然物体联系起来去理解它的原理。让我们拿交通工具来做个比方。
设计图
为了构建交通工具我们需要一份设计图。这份设计图可以定义交通工具的车轮的数量、颜色等等。一种交通工具通过一定的属性和行为来定义。在PHP中这些属性和行为就叫做变量和方法(函数)。描述一个对象的一组变量和方法就构成了一个“类”。
扩展的设计图
因为有各种不同类型的交通工具,比如汽车、自行车和摩托车。我们需要一种方法,它可以让我们为各种交通工具增加新功能的同时也可以使用交通工具的一般性的方法,换句话说,因为“履带”要用在所有类型的交通工具上面,我们不需要再重新编写这种方法。我们能够“继承”来完成这个功能。假如我们创建一个从“交通工具”继承过来的“汽车”的类,所有在“交通工具”类中的方法将被“汽车”类继承。
抽象
抽象的目的只关注于一个复杂对象的部分性质,为了解决你的问题需要你去构建一个考究的对象。你可以很容易的得到一辆汽车成千上万的属性,但是如果你需要设计一个程序去保存一个汽车经销商的目录,那么你应该只需要一个包含10多个属性的子集。这样一辆汽车被抽象成一个适合编程使用的汽车对象.
包装
包装可以隐藏一组方法的内容工具机制而只提供给用户一个定义良好的借口。在面向对象程序编程中,包装使得对象的数据结构和方法组合在一起。最容易理解“包装”的方式可以参考电话机。当今消费者可以购买各式各样的电话机,虽然这些电话机的内部设计方法可能不同,但是所有这些电话机器都能够通过一个标准的公共接口通讯。这就是包装的思想.
一个类可以定义新数据类型。PHP本身具有变量类型,比如字符串变量和浮点类型变量。但是通过类你可以设计自己的数据类型比如船、用户参考手册和数据库等等。一个类定义这种数据类型的属性和行为(成员变量和方法)。下面的例子显示如何定义一个包含属性和方法的类。
让我们看一下我们的交通工具的实际的例子
<?php/*** 如何定义一个类*/class Class_Name{[var 变量定义][Function 方法定义]}?>----------交通工具类------------<?phpclass vehicle{/*** 属性*/var $property1;var $property2;var $property3;/*** 方法*/function setTires($type){if ($type == "Firestone"){$this->property1 = "Must be a Ford SUV";}}function color($col){$this->property2 = $col;}}?>
如何使用定义好的类
类定义好以后,我们就可以建立它的实例。为了使用刚才的例子,我们在下面创建一个“交通工具”类的实例。
<?php$myCar = new vehicle();$myCar->setTires("Firestone");?>
使用类中的变量
最大的不同点在于使用一个对象和对象拥有的值的种类。一个字符串变量倒是很容易理解,因为它拥有一个值。
$myStr = "PHP stands for... uh.. i forget";
然而一个对象可以拥有任何种类的值
$myCar->year = 1988;
$myCar->value = 813.77;
$myCar->hasAirbag = false;
$myCar->color = "periwinkle";
在PHP中,一个对象的所有成员变量默认是公有的。没有办法可以强迫一个对象的访问属性,但是如果希望一个变量是私有变量的话,我们可以用一种强调的方式来实现。
$this pointer
如果你想调用一个对象的方法,你可以使用 '$this'来调用此对象指定实例的成员变量。刚开始,你可能对这个有点不理解,让我们来看个例子。首先,假设你有两辆汽车。
$myCar = new vehicle();
$spousesCar = new vehicle();
现在你有了同一个类的两个对象。你可能也听过这样的说法,“现在你有了同一个用户定义变量类型的两个综合变量”。 These are just different ways of talking about the same OOP concepts.
每个变量,$myCar 和 $spousesCar, 拥有这个类的独立的一套属性。
$myCar->property1;
//这两个是不同的
$spousesCar->property1;
//即使property1只在类定义中出现一次。你必须清楚,它仅仅是为了构成一个新数据类型而设计的。
但是在这个类内只有一个setTires()函数。当我们使用下面的语句的时候,它如何了解是谁调用了它呢?
$myCar->setTires("Firestone");
呵呵,现在这个$this就起作用了。在一个指定对象调用类内部的函数时候,这个对象就自动作为一个参数传递。用$this是出于方便的需要。看看下面的例子你应该可以理解。
$myCar->setTires("Firestone");/*** 方法*/function setTires($type){if ($type == "Firestone"){$this->property1 = "Must be a Ford SUV";}}//$this 代表 $myCar 变量$spousesCar->setTires("Goodyear");/*** 方法*/function setTires($type){if ($type == "Firestone"){$this->property1 = "Must be a Ford SUV";}}//现在它就代表 $spousesCar.
创建一个构造器
在一个类的实例被创建以后,如果开发者希望能有一个“默认”的函数可以调用,该怎么办呢?这就是要用到“构造器”
其实你只需要简单的将构造器的名字定义为类的名字就可以实现。现在你每次创建这个类的对象的时候,这个构造器方法将被调用。
类的继承
我们以前说过,一个类可以继承另一个类;但是我们如何利用这种功能呢?在一个系统中,许多变量起相同的作用,仅仅一些的作用有些不同,继承是非常有用的。继承是一种方法,通过这种方法,一个类可以用另外一个类作为模板来建立自身。继承类将把在被继承类中定义的成员变量和方法继承过来。通过延伸或者继承过来的类叫做子类。被继承类的叫做超类或父类。这样可以使类之间的作用不同并且不会影响现存的代码.现在让我们看个例子。
class Airplane {var $tirePressure;var $fuelLevel;var $passengerLimit;function takeOff() {...}function land() {...}function preFlightCheck() {}}class sevenFortySeven extends Airplane {function preFlightCheck() {//747飞机起飞预备工作}}class biplane extends Airplane {function preFlightCheck() {//双翼飞机起飞预备工作}}$planeArray[] = new biplane();$planeArray[] = new sevenFortySeven();$planeArray[] = new sevenFortySeven();$planeArray[] = new biplane();for ($x = 0; $x < count($planeArray); $x++) {$currentPlane = $planeArray[$x];if ($currentPlane->preFlightCheck() ) {$currentPlane->takeOff();//不管是什么型号的飞机,它都会知道它要起飞了} else {print "飞机出了点问题.";}}
类的静态方法
当处理一个类的对象的时候,你可能放一个对这个对象有用的函数在这个类中,而不是再另写一个特殊类。这样的函数叫做静态方法。一个良好
类应该包含所有有用的(utility)函数。
class Money {function addTax($amount,$percent){return $amount + ($amount * $percent);}function convertCurrency ($amount, $from, $to) {//在数据库中查找一个从$from变换到$to的转换率return $amount * $rate;}}$total = Money::addTax($subtotal,6.5);$yen = Money::convertCurrency ($usd, "america", "japan");
方法工厂(Factory Methods)
有时候将代码分成一个一个的块去创建对象很有好处。你可以使用大量的类,也可以使用一个类来决定对象使用工厂类(factory methods)。
工厂类可以帮助你有效的组织你的代码。一般情况下,工厂类包含一个比较大的转换声明并且返回一个合适的对象的实例。让我们看个有关C扫描
仪的例子。有一个Item基本类, 但是也有很多子类,这些子类可以为各种各样的产品调用(比如电子类的, 服装类的...)。
Class Item {var $price;var $isTaxable;var $properties;function getNewItem($upc) {//连接到数据库//查找$upc的类型并将其放入$type变量中//查找$upc的属性并将其放如$attrib变量中;return new $type($attrib);}}class produce extends Item {function produce ($a) {$this->properties = $a;}function requiresScale() {return true;}}class hardlines extends Item {function hardlines ($a) {$this->properties = $a;}function requiresSclae() {return false;}}while ( $upc = $scanner->next_code() ) { //假设有一个扫描仪的类$z = Item::getNewItem($upc);if ($z->requiresScale() ) {echo "需要尺寸!";}$subtotal += $z->properties["price"];}