从零开始攻略PHP(7)——面向对象(上)

1.理解面向对象的概念

  面向对象软件的一个重要优点是支持和鼓励封装的能力。封装也叫数据隐藏。

  在面向对象的软件中,对象是一个被保存数据和操作这些数据的操作方法的唯一、可标识的集合。

  对象可以按类进行分类。

  面向对象的编程语言必须支持多态性,多态性的意思是指不同的类对同一操作可以有不同的行为。语言支持多态性,可以知道将哪个操作应用于一个特定的对象。

  多态性与其说是对象的特性,不如说是行为的特性。在PHP中,只有类的成员函数可以是多态的。

  例如,尽管自行车的“移动”和汽车的“移动”在概念上是相似的,但是移动一辆自行车和移动一辆汽车所包含的行为是完全不同的。一旦行为作用的对象确定下来,动词“移动”就可以和一系列特定的行为联系起来。

  继承允许我们使用子类在类之间创建层次关系。子类将从它的超类继承属性和操作。

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

  当创建一个PHP类的时候,必须使用关键词“class”。

  2.1 类的结构

  如下所示代码创建了一个名为“classname”的类,它具有两个属性$attribute1和$attribute2:

class classname{

  public $attribute1;

  public $attribute2;

}

  通过在类定义中声明函数,可以创建类的操作。

class classname{

  function operation1()

  {

  }

  function operation2($param1,$param2)

  {

  }

}

  2.2 构造函数

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

  构造函数其名称必须是__construct()。这是PHP5中的变化。尽管可以手工调用构造函数,但其本意是在创建一个对象时自动调用。声明一个具有构造函数的类:

class classname{

  function __construct($param){

    echo “Constructor called with parameter ”.$param.”<br />”;

  }

}

  PHP支持函数重载,这就意味着可以提供多个具有相同名称以及不同数量或类型的参数的函数。

  2.3 析构函数

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

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

3.类的实例化

  在声明一个类后,需要创建一个对象(一个特定的个体,即类的一个成员)并使用这个对象。这也叫创建一个实例或实例化一个类。可以使用关键词“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();

  运行发现以下报错:

  $c的参数补上:

class classname{

  function __construct($param){

    echo "Constructor called with parameter ".$param."<br />";

  }

}

$a = new classname("First");

$b = new classname("Second");

$c = new classname("");

4.使用类的属性

  在一个类中,可以访问一个特殊的指针——$this。如果当前类的一个属性为$attribute,则当在该类中通过一个操作设置或访问该变量时,可以使用$this->attribute来引用。

  如下所示的代码说明了如何在一个类中设置和访问属性:

class classname{

  public $attribute;

  function operation($param){

    $this->attribute = $param;

    echo $this->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()函数需要两个参数,分别是:要被设置值的属性名称和要被设置的值。

  我们并不会直接访问这些函数。这些函数名称前面的双下划线表明在PHP中这些函数具有特殊的意义,就像__construct()函数和__destruct()函数一样。

  这些函数的工作原理是怎样的?如果实例化一个类:

$a = new classname();

  可以用__get()函数和__set()函数来检查和设置任何属性的值。

  如果使用如下命令:

$a -> $attribute = 5;

  该语句将间接调用__set()函数,将$name参数的值设置为“attribute”,而$value的值被设置为5。必须编写__set()函数来完成任何所需的错误检查。

  __get()函数的工作原理类似。如果在代码中引用:

$a -> attribute;

  该语句将间接调用__get()函数,$name参数的值为“attribute”。我们可以自己决定编写__get()函数来返回属性值。

  我们只使用一段代码来访问特定的属性。只有一个访问入口,就可以实现对要保存的数据进行检查,这样就可以确保被保存的数据是有意义的数据。

  如果后来发现$attribute属性值应该是0到100之间,我们就可以添加几行代码,在属性值改变之前进行检查:

function _set($name, $value){

  if(($name=”attribute”)&&($value>=0)&&($value<=100))

    $this->attribute = $value;

}

  通过单一的访问入口,可以方便地改变潜在的程序实现。

  无论需要做什么样的改变,只要修改访问器函数即可。只要保证这个访问器函数仍然接收并返回程序的其他部分期望的数据类型,那么程序的其他部分代码就不会受影响。

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

  PHP支持如下3种访问修饰符:

  · 默认选项是public。公有的属性或方法可以在类的内部和外部进行访问。

  · private访问修饰符意味着被标记的属性或方法只能在类的内部进行访问。

  · protected可以理解成位于private和public之间的关键字,后面会详细探讨。

6.类操作的调用

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

  如果有如下类:

class classname{

  function operation1()

  {

  }

  function operation2($param1,param2)

  {

  }

}

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

$a = new classname();

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

$a -> operation1();

$a -> operation2(12,”test”);

  如果操作具有返回值,可以捕获到如下所示的返回数据:

$x = $a->operation1();

$y = $a->operation2(12,”test”);

7.在PHP中实现继承

  继承是单方向的。子类可以从父类或超类继承特性,父类缺不能从子类继承特性。

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

  可以使用private和protected访问修饰符来控制需要继承的内容。 如果一个属性或方法被指定为private,它将不能被继承。

  如果一个属性或方法被指定为protected,它将在类外部不可见(就像一个private元素),但是可以被继承。

  考虑如下实例:

<?php

class A{

  private function operation1(){

    echo "operation1 called";

  }

  protected function operation2(){

    echo "operation2 called";

  }

  public function operation3(){

    echo "operation3 called";

  }

}

class B extends A{

  function __construct(){

    $this->operation1();

    $this->operation2();

    $this->operation3();

  }

}

$b = new B;

?>

  $this->operation1();这句将产生报错:

  说明私有操作不能在子类中调用。

  如果注释掉这一行,其他两个函数调用将正常工作。

  protected函数可以被继承但是只能在子类内部使用。如果尝试在该文件结束处添加如下所示的代码:

$b->operation2();

  将产生如下报错:

  7.2 重载

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

  例如,如果有类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()函数:

  注意$this->后的变量不带$符

  如果创建了类B的一个对象:

$b = new B();

$b -> operation();

  与子类中定义新的属性和操作并不影响超类一样,在子类中重载属性或操作也不会影响超类。

  如果不使用替代,一个子类将继承超类的所有属性和操作。如果子类提供了替代定义,替代定义将有优先级并且重载初始定义。

  parent关键字允许调用父类操作的最初版本。例如,要从类B中调用A::operation,可以使用如下所示的语句:

parent::operation();

  但是,其输出结果却是不同的。虽然调用了父类的操作,但是PHP将使用当前类的属性值。

  源码:

<?php

class A {

    public $attribute = "default value";

    function operation() {

        echo "Something<br />";

        echo "The value of \$attribute is ".$this->attribute."<br />";

    }

}

class B extends A {

    public $attribute = "different value";

    function operation() {

        echo "Something else<br />";

        echo "The value of \$attribute is ".$this->attribute."<br />";

    }

    function Aoperation() {

        parent::operation();

    }

}

$a = new A();

$a->operation();

$b = new B();

$b->Aoperation();

?>

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

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

  当在一个函数声明前面使用final关键字时,这个函数将不能被任何子类中被重载。也可以使用final关键字来禁止一个类被继承。

  7.4 PHP不支持多重继承

  如题,每个类只能继承一个父类。一个父类可以有多少个子类则并没有限制。

  7.5 实现接口

  如果需要实现多重继承功能,在PHP中,可以通过接口。接口可以看作是多重继承问题的解决方法。

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

interface Displayable{

  function display();

}

class webPage implements Displayable{

  function display(){

    // ...

  }

}

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

  如果没有实现接口中指定的方法,将产生一个致命错误。

整理自《PHP和MySQL Web》开发

时间: 2024-10-10 15:01:45

从零开始攻略PHP(7)——面向对象(上)的相关文章

从零开始攻略PHP(5)——字符串操作与POSIX正则

一.字符串操作 1.字符串的格式化 1.1 干掉空格 trim()函数可以除去字符串开始位置和结束位置的空格,并将结果字符串返回. ltrim()函数可以除去字符串开始位置的空格. rtrim()函数可以除去字符串结束位置的空格. 1.2 格式化字符串以便显示 nl2br()函数将字符串作为输入参数,用HTML中的<br />标记代替字符串中的换行符. printf()函数将一个格式化的字符串输出到浏览器中. sprintf()函数返回一个格式化了的字符串. 当在类型转换代码中使用printf

从零开始攻略PHP(4)——数组的使用

1.数组的概念 数组就是一个用来存储一系列变量值的命名区域. 每个数组元素有一个相关的索引(也成为关键字),它可以用来访问元素. PHP允许间隔性地使用数字或字符串作为数组的索引. 2.数字索引数组 2.1 数字索引数组的初始化 $products = array(‘Tires’,’Oil’,’Spark Plugs’); 如果需要将按升序排列的数字保存在一个数组中,可以使用range()函数自动创建这个数组. 创建一个1-10的数字数组: $numbers = range(1,10); 可选的

从零开始攻略PHP(6)——代码重用与函数编写的一些注意事项

一个新的项目是这样创建的:它将已有的可重新利用的组件进行组合,并将新的开发难度降低到最小. 代码重用的好处:降低成本.提升可靠性和一致性. 1.使用require()和include()函数 使用一条require()或include()语句,可以将一个文件载入到PHP脚本中. require()和include()几乎相同.区别是函数失败后,require()函数将给出一个报错.Include()给的则是警告. 变体函数分别是require_once()和include_once().作用是确

狮城五日穷游攻略(上)

原文链接:http://chengyuanlaodao.com/chatter/狮城五日穷游攻略_上/ 前几天有个朋友来新加坡玩,让我帮他安排一下行程.他刚工作不久,预算不太充裕,所以帮他做了这篇穷游攻略.高富帅不差钱的请自觉点右上角的红叉叉. 首先列出最后的花销列表(两人),单位是软妹币:签证 300机票 3700 (酷航南京往返)住宿五晚 1200各类门票 1290 (包含环球影城 动物园 摩天轮 海洋馆 时光之翼)交通费+手机费+吃喝 1000 签证新加坡现在不允许个人游客自己去办旅游签证

在电脑上测试手机网站全攻略

最近公司要开发网站的移动版,让我准备准备知识,话说本人开发移动网站的经验还真不多,最悲剧的事情就是我的手机是个经典的诺基亚,而且公司还不给配手机,这是有多扣啊,没办烦啦,没有手机就用电脑模拟呗,相办法代替,查了很多资料,尝试了大部分方法,下面将这一天的努力总结下分享给大家,也让大家免去看那么多文章,以下介绍的方法,都是本人亲自测试成功的方法. Chrome* chrome模拟手机总共有四种方法,原理都一样,通过伪装User-Agent,将浏览器模拟成Android设备.以下标星的为推荐方法. 1

用友U8客户端连接不上服务器全攻略

用友U8客户端连接不上服务器全攻略 http://www.enet.com.cn2009年09月23日09:26 来自论坛 [导读]:如果网络不通,就让用户查找网络原因 检查步骤: 1.网络是否通? 方法:ping 服务器名称/ip -t 如果网络不通,就让用户查找网络原因: 如果网络是通的,继续…… 2.尝试使用ip地址登录服务器 如果无效,继续…… 3.配置hosts文件,将服务器+ip加入(路径:C:\WINNT\system32\drivers\etc\hosts) 如果配置hosts文

App上线流程全攻略(史上最详细步骤)

@转载请保留:iOS界一迷糊小书童--->专注于iOS开发!!谢谢合作 /*****************************************1************************************************/ /*****************************************2************************************************/ /*3(我这里省了创建证书,创建证书和真机调试里面差别不

上云攻略强势来袭-华为企业云服务

第二期:云端高性能计算,弹性云服务器使用攻略 http://support.hwclouds.com/cloud_raiders/second-phase.html 第三期:云端高性能计算,弹性云服务器热门问题集锦 http://support.hwclouds.com/cloud_raiders/third-phase.html 第四期:云端高可靠的分布式存储,云硬盘使用指南 http://support.hwclouds.com/cloud_raiders/fourth-phase.html

生成 PDF 全攻略【2】在已有PDF上添加内容

项目在变,需求在变,不变的永远是敲击键盘的程序员..... PDF 生成后,有时候需要在PDF上面添加一些其他的内容,比如文字,图片.... 经历几次失败的尝试,终于获取到了正确的代码书写方式. 在此记录总结,方便下次以不变应万变,需要的 jar 请移步:生成PDF全攻略 PdfReader reader = new PdfReader("E:\\A.pdf"); PdfStamper stamper = new PdfStamper(reader, new FileOutputStr