面向对象的PHP

面向对象的概念

对于程序开发来说, 当今编程语言大多支持甚至要求使用面向对象的方法。面向对象(OO)的开发方法试图在系统中引入对象的分类、 关系和属性, 从而有助于程序开发和代码重用。

一、类和对象

在面向对象软件的上下文中, 对象可以用于表示几乎所有实物和慨念一一可以表示物理对象, 例如 “ 桌子” 或者“客户 ”;也可以表示只有在软件中才有意义的概念性对象, 如 “文本输入区域” 或者”文件”。通常, 在软件中, 我们对对象最感兴趣,这些对象当然既包括现实世界存在的实物对象, 也包括需要在软件中表示的概念性对象。

面向对象软件由一系列具有属性和操作的自包含对象组成,这些对象之间能够交互,从而达到我们的要求。对象的属性是与对象相关的特性或变量。对象的操作则是对象可以执行的、用来改变其自身或对外部产生影响的方法、行为或函数(属性可以与成员变量和特性这些词交替使用,而操作也可以与方法交替使用)。

面向对象软件的一个重要优点是支持和鼓励封装的能力一封装也叫数据隐藏。从本质上说, 访问一个对象中的数据只能通过对象的操作来实现,对象的操作也就是对象的接口。

在面向对象的软件中,对象是一个被保存数据和操作这些数据的操作方法的唯一、可析、识的集合。例如,我们可以定义两个代表按钮的对象,虽然它们具有相同的“OK"标签,而且宽都是60像素,高都是20像素,其他属性也都相同,但是仍然要将两个按钮作为不同的对象处理。 在软件中,我们用不同的变量作为对象的句柄(唯一标识符)。

对象可以按类进行分类。类是表示彼此之间可能互不相同,但是必须具有一些共同点的对象集合。虽然类所包含的对象可能具有不同属性值,但是,这些对象都具有以相同方式实现的相同操作以及表示相同事物的相同属性。

名词“自行车”可以被认为是描述了多辆不同自行车的类,这些对象具有相同的特性或属性(譬如两个车轮,一种颜色和一种尺寸大小)以及相同的操作(例如,移动)。

我自己的自行车可以被认为是这种自行车类的一个对象。它拥有所有自行车的共同特征,与其他自行车一样,都有一个操作一一移动,移动方式也与其他自行车一样,虽然我的自行车很少 使用。它的属性却有唯一值,因为我的自行车是绿色的,并不是所有自行车都是这种颜色的。

二、多态性

面向对象的编程语言必须支持多态性,多态性的意思是指不同的类对同一操作可以有不同的行为。例如,如果定义了一个“汽车”类和一个“自行车”类,二者可以具有不同的“移动” 操作。对于现实世界的对象,这并不是一个问题。我们不可能将自行车的移动与汽车的移动相混淆。然而,编程语言并不能处理现实世界的这种基本常识,因此语言必须支持多态性,从而 可以知道将哪个移动操作应用于一个特定的对象。

多态性与其说是对象的特性, 不如说是行为的特性。 在PHP中, 只有类的成员函数可以是多态的。 这可与现实世界的自然语言的动词做比较, 后者相当于成员函数。 可以想像一下生活 中我们是如何使用自行车的。 我们可以清洗、 移动 、 拆解、 修理和刷油漆等。
这些动词只描述了普遍行为, 因为我们不知道这些行为应该作用于哪种对象(这种对对象和行为的抽象是人类智慧的一个典型特征)。

三、继承

继承允许我们使用子类在类之间创建层次关系。子类将从它的超类继承属性和操作。 例如,汽车和自行车具有一些共同特性。 我们可以用一个名为交通工具的类包含所有交通工具都具有的“颜色” 属性和 “ 移动” 行为, 然后让汽车类和自行车类继承这个交通工具类。

作为术语, 你将看到子类和派生类的交替使用。 同样地, 你还将看到超类和父类的交替使用。
通过继承, 我们可以在已有类的基础上创建新类。 根据实际需要, 可以从一个简单的基类开始, 派生出更复杂、 更专门的类。 这样, 可以使代码具有更好的可重用性。 这就是面向对象 方法的一个重要优点。

如果操作可以在一个超类中编写一遍而不需要在每个子类中都编写, 那么就可以利用继承 省去大量重复的编码工作。

在PHP中创建类、属性和操作

到目前为止, 我们已经以非常抽象的方式介绍了类。当创建一个PHP类的时候, 必须使用 关键词 “class”。

一、类的结构

一个最小的 、 最简单的类定义如下所示:

classs classname{
}

为了使以上类具有实用性, 类需要添加一些属性和操作。 通过在类的定义中使用某些关键词来声明变量, 可以创建属性。 这些关键字与变量的作用域相关: public、 private和protected

通过在类定义中声明函数,可以创建类的操作。如下所示的代码创建一个名为classname的类,该类包含两个不执行任何操作的方法,其中operation1()不带参数,而操作operation2()带两个参数:

class classname{
function operation1()
 {
 }
function operation2($param1,$param2)
 {
 }
}
二、构造函数

大多数类都有种称为构造函数的特殊操作。当创建一个对象时它将调用构造函数,通常,这将执行一些有用的初始化任务:例如,设置属性的初始值或者创建该对象需要的其他对象。

构造函数的声明与其他操作的声明一样,只是其名称必须是__construct()。这是PHP5中的变化。尽管可以手工调用构造函数,但其本意是在创建一个对象时自动调用。如下所示的代码声明了一个具有构造函数的类:

class classname 
{
function __constrcut($param)
{
    echo " constructor called with parameter ".$param."<br/>";
}
}

如今,PHP支持函数重载,这就意味着可以提供多个具有相同名称以及不同数量或类型的参数的函数(该特性在许多面向对象语言中都支持)。

三、析构函数

与构造函数相对的就是析构函数。析构函数允许在销毁一个类之前执行一些操作或完成一些功能,这些操作或功能通常在所有对该类的引用都被重置或超出作用域时自动发生。

与构造函数的名称类似,一个类的析构函数名称必须是__destruct()。析构函数不能带有任何参数。

类的实例化

在声明一个类后,需要创建一个对象(一个特定的个体,即类的一个成员)并使用这个对象。这也叫创建一个实例或实例化一个类。可以使用关键词”new”来创建一个对象。需要指定创建的对象是哪一个类的实例,并且通过构造函数提供任何所需的参数。

如下所示的代码声明了一个具有构造函数、名为Classname的类,然后又创建3个classname类型的对象。

class classname
{
    function __construct($param)
    {
    echo "Constructor called with parameter".$param."<br/>";
    }
}
$a = new classname("First");
$b = new classname("Second");
$c = new classname();

由于在每次创建一个对象时都将调用这个构造函数,以上代码将产生如下所示的输出:

Constructor called with parameter First
Constructor called with parameter Second 
Constructor called with parameter  

使用类的属性

在一个类中,可以访问一个特殊的指针一一$this。如果当前类的一个属性为$attribute,则当在该类中通过一个操作设置或访问该变量时,可以使用$this->attribute来引用。
如下所示的代码说明了如何在一个类中设置和访问属性:

class classname
{
    public $attribute;
    function operation($param)
    {
    $this->attribute = $param
    echo $this->attribute;
    }
}

是否可以在类的外部访问一个属性是由访问修饰符来确定的,这个例子没有对属性设置限制的访问,因此可以按照如下所示的方式从类外部访问属性:

class classname
{
    public $attribute;
}
$a = new classname();
$a->attribute = "value";
echo $a->attribute;

通常, 从类的外部直接访问类的属性是糟糕的想法。 面向对象方法的一个优点就是鼓励使用封装。 可以通过使用__get()__set()函数来实现对属性的访问。 如果不直接访问一个类的属性而是编写访问函数,那么可以通过一段代码执行所有访问。当最初编写访问函数肘,访问函数可能如下所示:

class classname
{
    public $attribute;
    function __get($name)
    {
        return $this->$name;
    }
    function __set($name,$value)
    {
    $this->$name = $value;
    }
}

以上代码为访问$attribute属性提供了最基本的功能。__get ()函数返回了$attribute 的值, 而__set ()函数只是设置了$attribute的值。

请注意,__get()函数带有一个参数(属性的名称)并且返回该属性的值。__set ()函数需要两个参数, 分别是:要被设置值的属性名称和要被设置的值。

使用private和public关键字控制访问

PHP提供了访问修饰符。 它们可以控制属性和方法的可见性。 通常, 它们放置在属性和方法声明之前。 PHP支持如下3种访问修饰符:

1.默认选项是public, 这意味着如果没有为一个属性或方法指定访问修饰符, 它将是 public。 公有的属性或方法可以在类的内部和外部进行访问。
2.private访问修饰符意味着被标记的属性或方在去只能在类的内部进行访问。 如果没有 使用__get()__set()方法, 你可能会对所有属性都使用这个关键字。 也可以选择使得部分方法成为私有的, 例如, 如果某些方法只是在类内部使用的工具性函数。 私有 的属性和方法将不会被继承。
3.protected访问修饰符意味着被标记的属性或方法只能在类内部进行访问。 它也存在于任何子类; 同样, 在本章的稍后讨论继承问题的时候, 我们还将回到这个问题。 在这里, 可以将protected理解成位于private和public之间的关键字。

类操作的调用

与调用属性大体上相同, 可以使用同样的方式调用类的操作。 如果有如下类:

class classname
{
    function operation1()
    {
    }
    function operation2($param1,$param2)
    {
    }
}

并且创建了一个类为classname 、 名称为$a的对象, 如下所示:

$a = new classname();

可以像调用其他函数一样调用操作:通过使用其名称以及将所有所需的参数放置在括号中。 因为这些操作属于一个对象而不是常规的函数, 所以需要指定它们所属的对象。 对象名称的使用方法与对象属性一样, 如下所示:

$a->operation1();
$a->operation2(12,"test");

在PHP中实现继承

如果类是另一个类的子类, 可以用关键词”extends”来指明其继承关系。 如下代码创建了一个名为B的类, 它继承了在它前面定义的类A。

class B extends A
{
    public $attribute2;
    function operation2()
    {
    }
}

如果类A具有如下所示的声明:

class A
{
    public $attribute1;
    function operation1()
    {
    }
}

则如下所示的所有对类B对象的操作和属性的访问都是有效的:

\$b = new B () ; 
\$b->operation1(); 
\$b->attributel = 10; 
\$b->operation2(); 
\$b->attribute2 = 10; 

请注意, 因为类B派生于类A,所以可以使用操作operation1 ()和属性$attribute1,尽管这些操作和属性是在类A里面声明的。 作为A的子类,B具有与A一样的功能和数据。此外,B还声明了自己的一个属性和一个操作。

值得注意的是, 继承是单方向的。 子类可以从父类或超类继承特性, 而父类却不能从子类继承特性。

一、通过继承使用private和protected访问修饰符控制可见性

可以使用private和protected访问修饰符来控制需要继承的内容。如果一个属性或方法被指定为private,它将不能被继承。如果一个属性或方法被指定为protected,它将在类外部不可见(就像一个private元素),但是可以被继承。

二、重载

我们已经介绍了如何在子类中声明新的属性和操作。 在子类中, 再次声明相同的属性和操作也是有效的, 而且在有些情况下这将会是非常有用的。 我们可能需要在子类中给某个属性赋予一个与其超类属性不同的默认值, 或者给某个操作赋予一个与其超类操作不同的功能,这就叫重载
例如,如果有类A:

class A
{
    public $attribute = "default value";
    function operation()
    {
        echo "Something<br/>";
        echo "The Value of \$attribute is".$this->attribute."<br/>";
    }
}

现在,如果需要改变$attribute的默认值,并为operation()操作提供新的功能,可以创建类B,它重载了$attribute和operation()方法,如下所示:

class B extends A
{
    public $attribute = "different value";
    function operation()
    {
        echo "Something else <br/>";
        echo "The Value of \$attribute is" .$this->attribute."<br/>";
    }
}

声明类B并不会影响类A的初始定义。考虑如下所示的两行代码:

$a = new A () ; 
$a -> operation (); 

这两行代码创建了类A的一个对象并且调用了它的operation()函数。这将产生如下所示的输出:

Some thing
The value of $attribute is default value 

以上结果是在创建类B没有改变类A的前提下产生的。如果创建了类B的一个对象,将得到不同的输出结果。
如下所示的代码:

$b = new B(); 
$b -> operation();

将产生如下所示的结果:

Something else 
The value of $attribute is different value 

继承可以是多重的。可以声明一个类C,它继承了类B,因此继承了类B和类B父类的所有特性。类C还可以选择重载和替换父类的那些属性和操作。

三、使用final关键字禁止继承和重载

PHP提供了final关键字。当在一个函数声明前面使用这个关键字肘,这个函数将不能在任何子类中被重载。例如,可以在上一个示例的类A中添加这个关键字,如下所示:

class A
{
public $attribute = "default value";
final function operation()
{
    echo "something <br/>";
    echo "The Value of \$attribute is".$this->attribute."<br/>";
}
}

使用这个方法可以禁止重载类B中的operation()方法。如果尝试这样操作,将看到如下所示的错误:

Fatal error: Cannot override final method A: :operation() 

也可以使用final关键字来禁止一个类被继承。要禁止一个类被继承,可以按如下所示的方式使用final关键字:

final class A
{...}
四、多重继承

少数的面向对象语言(最著名的就是C++和Smalltalk)支持多重继承,但是与大多数面向对象语言一样,PHP并不支持多重继承。也就是说,每个类都只能继承一个父类。一个父类可以有多少个子类并没有限制。

五、实现接口

如果需要实现多重继承功能,在PHP中,可以通过接口。接口可以看作是多重继承问题的解决方法,而且类似于其他面向对象编程语言所支持的接口实现,包括Java。

接口的思想是指定一个实现了该接口的类必须实现的一系列函数。例如,需要一系列能够显示自身的类。除了可以定义具有display()函数的父类,同时使这些子类都继承该父类并重载该方法外,还可以实现一个接口,如下所示:

interface Displayable
{
    function display();
}
class webpage implements Dislayable
{
    function display()
    {
    //...
    }
}

以上代码示例说明了多重继承的一种解决办法,因为webPage类可以继承一个类,同时又可以实现一个或多个接口。

类的设计

我们已经了解了对象和类的一些核心概念, 以及如何在PHP中实现它们的语法。 在接下来的内容中, 我们将开始介绍如何设计这些有用的类。

代码中的许多类都将表示现实世界中对象的种类或类别。 在Web开发中可能使用的类可能包括网页、 用户界面组件、 购物车、 错误处理、 商品分类或顾客。
在之前, 我们使用简单的包含文件实现了假想公司一TLA咨询公司, 使其网站的不同页面具有和谐统一的外观。 通过使用节省时间与精力的类和继承, 可以创建该网站更高级的版本。

现在, 我们希望能尽快为TLA公司设计风格一致的网页。 而且, 这些页面应该能够通过修改以便适合网站的不同部分。

为了实现这个例子, 我们准备创建一个Page类, 其主要目的是减少创建一个新页面所需的HTML代码。 这样在修改页面的时候只要修改页面不同的部分, 而相同的部分会自动生成。该类应该为建立新页面提供灵活的框架, 但不应该限制创作的自由。

由于我们是通过动态脚本语言而不是静态的HTML来创建页面的, 所以可以在页面上增加许多巧妙的东西, 其中包括如下所示的功能:

1.允许在需要修改某些页面元素的时候, 只在一处进行修改。 例如, 如果要修改 “注册商标”提示或增加一个按钮, 只需在一个地方修改即可。
2.页面大部分区域都有默认内容, 但能够在需要的地方修改每个元素, 定制如标题或标签 这类元素的值。
3.识别哪一个页面是当前浏览页, 并相应改变导航条一一例如, 在首页中有一个指向首页的链接是没有意义的。
4.允许使用特定的页面代替标准页面。 例如, 如果需要在网站的不同地方使用不同的导航 条, 应该能够替换掉标准导航条。

编写类代码

类需要一个逻辑的名称。因为它代表一个页面,所以称之为page。要声明这个page类,可以使用如下所示的代码:

class page
{
}

Page类需要一些属性, 需要将那些可能要在页与页之间不断修改的元素设置为类的属性。
页面的主要内容, 也就是HTML标签和文本的组合, 我们将其命名为$content。可以在类定义中使用如下所示的代码来声明它:

public $content; 

也可以设置属性来保存页面的标题。 我们可能会对其进行修改, 从而确保能够清楚地显示访问者浏览的特定页面。为了不让页面标题为空, 可以使用如下所示的声明来提供一个默认标题:

public $title"TLA Consulting Pty Ltd "

大多数商业网站的网页都包含了metatags, 这样便于搜索引擎对其检索。 为了使其更实用, 不同页面的metatags应该尽可能不 同。同样, 我们可以提供一个默认值,如下所示:

public $keywords = "TLA Consulting, Three Letter Abbreviation some of my best friends are search engines;

(请参阅前面)显示的原始页面上的导航条应该在每一页面都应该相同, 这样可以避免浏览者混淆。 但为了使它们修改起来更加容易, 我们也赋给它们一个属性。 由于按钮的数量在不同页面可能会有所不间, 因此需要使用一个数组, 来保存按钮的文本标签以及该按钮指向的URL:

public $buttons = array"Home" => "home.php",
                        "Contact" =>"contact.php",
                        "Services" =>"services.php",
                        "Site Map" =>"map.php"
                        );

PHP面向对象的高级功能

一、使用per-Class常量

PHP提供了Per-Class常量的思想。这个常量可以在不需要初始化该类的情况下使用, 如下所示:

<?php
    class Math{
    const pi = 3.14159;
    }
    echo "Math::pi = ".Math::pi."\n";
?>

可以通过使用”::”操作符指定常量所属的类来访问Per-Class常量, 如以上示例所示。

二、实现静态方法

PHP允许使用Static关键字。 该关键字适用于允许在未初始化类的情况下就可以调用的 方法。 这种方法等价于Per-Class常量的思想。

请注意, 在一个静态方法中, 不能使用this关键字。 因为可能会没有可以引用的对象实例。

三、检查类的类型和类型提示

instanceof关键字允许检查一个对象的类型。可以检查一个对象是否是特定类的实例,是否是从某个类继承过来或者是否实现丁某个接口。instanceof关键字是一个高效的条件操作符。

四、克隆对象

PHP提供了clone关键字,该关键字允许复制一个已有的对象。例如: $c= clone $b;
将创建与对象$b具有相同类的副本,而且具有相同的属性值。

五、使用抽象类

PHP还提供了抽象类。这些类不能被实例化,同样类方法也没有实现,只是提供类方法的声明,没有具体实现。

六、使用__call()重载方法

前面,我们介绍了有些具有特殊意义的类方法,这些方法的名称都是以双下划线开始的(__),我们来介绍__call()方法,该方法用于实现方法的重载。

方法的重载在许多面向对象编程语言中都是常见的, 但是在PHP中却不是非常有用, 因为我们习惯使用灵活的类型和(容易实现的)可选的函数参数。

__call()方法必须带有两个参数。 第一个包含了被调用的方法名称,而第二个参数包含了传递给该方法的参数数组。

七、使用__autoload()方法

它不是一个类方法,而是一个单独的函数,也就是说,可以在任何类声明之外声明这个函数。如果实现了这个函数,它将在实例化一个还没有被声明的类时自动调用。

__autoload()方法的主要用途是尝试包含或请求任何用来初始化所需类的文件。 分析如下示例:

function __autoload($name)
{
    include_once $name.".php";
}

该代码实现将包括一个具有与该类相同名称的文件。

八、实现迭代器和迭代

php的面向对象引擎提供了一个非常聪明的特性,也就是,可以使用foreach()方法通过循环方式取出一个对象的所有属性,就像数组方式一样。

九、将类转换成字符串

如果在类定义中实现了__toString()函数,当尝试打印该类时,可以调用这个函数,如下例所示:

$p = new Pr主nLable; 
echo $p; 

__toString()函数的所有返回内容都将被echo语句打印。例如,可以按下例所示实现这个方法:

class Printable
{
    public $testone;
    public $testtwo;
    public function __toString()
    {
    return(var_export($this.TRUE));
    }
}

(var_export()函数打印出了类中的所有属性值。)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值