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》开发
PHP学习(7)——面向对象(上)的更多相关文章
- Java基础学习(三)—面向对象(上)
一.理解面向对象 面向对象是一种思想,是基于面向过程而言的,就是说面向对象是将功能等通过对象来实现,将功能封装进对象之中,让对象去实现具体的细节:这种思想是将数据作为第一位,而方法或者说是 ...
- 0030 Java学习笔记-面向对象-垃圾回收、(强、软、弱、虚)引用
垃圾回收特点 垃圾:程序运行过程中,会为对象.数组等分配内存,运行过程中或结束后,这些对象可能就没用了,没有变量再指向它们,这时候,它们就成了垃圾,等着垃圾回收程序的回收再利用 Java的垃圾回收机制 ...
- 0028 Java学习笔记-面向对象-Lambda表达式
匿名内部类与Lambda表达式示例 下面代码来源于:0027 Java学习笔记-面向对象-(非静态.静态.局部.匿名)内部类 package testpack; public class Test1{ ...
- 0025 Java学习笔记-面向对象-final修饰符、不可变类
final关键字可以用于何处 修饰类:该类不可被继承 修饰变量:该变量一经初始化就不能被重新赋值,即使该值跟初始化的值相同或者指向同一个对象,也不可以 类变量: 实例变量: 形参: 注意可以修饰形参 ...
- 0013 Java学习笔记-面向对象-static、静态变量、静态方法、静态块、单例类
static可以修饰哪些成员 成员变量---可以修饰 构造方法---不可以 方法---可以修饰 初始化块---可以修饰 内部类(包括接口.枚举)---可以修饰 总的来说:静态成员不能访问非静态成员 静 ...
- C#学习笔记——面向对象、面向组件以及类型基础
C#学习笔记——面向对象.面向组件以及类型基础 目录 一 面向对象与面向组件 二 基元类型与 new 操作 三 值类型与引用类型 四 类型转换 五 相等性与同一性 六 对象哈希码 一 面向对象与面向组 ...
- Python学习之==>面向对象编程(二)
一.类的特殊成员 我们在Python学习之==>面向对象编程(一)中已经介绍过了构造方法和析构方法,构造方法是在实例化时自动执行的方法,而析构方法是在实例被销毁的时候被执行,Python类成员中 ...
- 程序设计基础·Java学习笔记·面向对象(下)
Java程序设计基础之面向对象(下) (补充了上的一些遗漏的知识,同时加入了自己的笔记的ヾ(•ω•`)o) (至于为什么分P,啊大概是为了自己查笔记方便(?)应该是("` 3′") ...
- MVC&WebForm对照学习:文件上传(以图片为例)
原文 http://www.tuicool.com/articles/myM7fe 主题 HTMLMVC模式Asp.net 博客园::首页:: :: :: ::管理 5 Posts :: 0 ...
- PHP学习之-面向对象
PHP学习之-面向对象 1.什么是对象 "世界万物皆对象",一切可以被抽象出来的东西都是对象.像花,草.看不到的"概念"都是对象. 2.对象的基本组成 a.属性 ...
随机推荐
- 在laravel5.8中集成swoole组件----用协程实现的服务端和客户端(二)---静态文件如何部署
目前,较为成熟的技术是采用laravelS组件,注意和laravel 区别laravelS多了一个大写的S,由于laravelS默认监听5200端口,所以laravel项目要做一些调整 例如: 静态文 ...
- 【luoguP3959 宝藏】-状压DP
题目描述: 参与考古挖掘的小明得到了一份藏宝图,藏宝图上标出了 n 个深埋在地下的宝藏屋, 也给出了这 n 个宝藏屋之间可供开发的m 条道路和它们的长度. 小明决心亲自前往挖掘所有宝藏屋中的宝藏.但是 ...
- ubuntu安装chrome driver
首先下载Chrome Driver(Firefox Driver的安装与该步骤相同) 链接: http://chromedriver.storage.googleapis.com/index.html ...
- 【强化学习】1-1-2 “探索”(Exploration)还是“ 利用”(Exploitation)都要“面向目标”(Goal-Direct)
title: [强化学习]1-1-2 "探索"(Exploration)还是" 利用"(Exploitation)都要"面向目标"(Goal ...
- neo4j 一些常用的CQL
创建节点.关系 创建节点(小明):create (n:people{name:’小明’,age:’18’,sex:’男’}) return n; 创建节点(小红): create (n:people{ ...
- oracle的事务
一.事务 保证数据的一致性,有一组相关的dml语句组成,该组的dml语句要么全部成功,要么全部失败 如:网上转账就是典型的要用事物来处理,用以保证数据的一致性 二.事务和锁 当执行事物操作时(dml语 ...
- Little Prince
You know — one loves the sunset, when one is so sad... 你知道的—当一个人情绪低落的时候,他会格外喜欢看日落...... If someone l ...
- UVA 11174 Stand in a Line,UVA 1436 Counting heaps —— (组合数的好题)
这两个题的模型是有n个人,有若干的关系表示谁是谁的父亲,让他们进行排队,且父亲必须排在儿子前面(不一定相邻).求排列数. 我们假设s[i]是i这个节点,他们一家子的总个数(或者换句话说,等于他的子孙数 ...
- 两个int值相乘超过int最大值
System.out.println(100000000*1000 ); //输出结果是:1215752192 先将100000000*1000 的结果转化为二进制: 10111 01001000 0 ...
- Nginx之 Location 的生成
1. Location 的生成 location 的生成大致有三种: 由 location 指令直接生成 命令 location:仅用于 server 内部跳转,如 rewrite 就是命名 loca ...