我的编程日记之八月十号

PHP基础知识已经学习得差不多了,从这节开始学习的PHP的面向对象程序开发的概念,对象比较抽象,理解起来也比较困难一些,但只要努力,多练习还是可以容易掌握的,对前面学习过的知道如回调函数的数组排序、正常的数组排序:http://blog.sina.com.cn/s/blog_8a66129101017mhx.html,删除数组元素、增加数组元素:http://blog.sina.com.cn/s/blog_8a66129101017l38.html等知识不了解的可以返回温习。

现在开始新的PHP基础知识的讲解——面向对象程序开发学习,早期时候,我们编写的程序是面向过程来进行代码的书写,现在的面向对象是脱离出面向过程的一个编程发展,使用起来也比面向过程方便了许多,因为我们只要增加或修改某个功能,只需要修改某个对象的方法就可以实现,所以学好面向对象编程是非常有必要的。现在从最基础的面向对象的类开始对面向对象进行讲解。

一、类

类的概念:类是一种抽象的概念,类是对象的基石,没有类就没有对象,并且类是具有相同语义定义对象的集合,使用具体的类是不可行的,只能对该类进行实例化出一个对象。

举个与生活相关的例子:假如我们使用的具体电脑就是一个对象,那么电脑就是一个类,类它是具体的方法与属性的集合,如电脑的属性有:颜色、品牌、型号等;电脑的方法(电脑的动作)有:电脑可以做什么具体的工作(如上网、玩游戏、设计等)。再如,如果我们去学校接小孩,如果你对老师说我要接小孩,那么老师是不可能不知道哪个小孩是我们的(除非这位老师认识我们),那么我们就需要对这个小孩进行具体的对象实例化到某某小孩,这样才能把小孩成功接回家。在现实生活中,我们可以这样理解,万物皆为对象,就是我们能想象到的任何东西都可以看成一个对象。

在程序当中在生成一个类是非常的简单的,具体操作如下:

class Pc{

}

通过关键词class加类名Pc就可以在程序里产生一个类,但是这个类是没有任何意义的,我们需要给这个类定义属性和方法,如我们定义的这个电脑Pc这个类,那么电脑的属性前面也说到,如颜色、品牌、型号等等;方法如上网、玩游戏等等。现在我们就来定义一下这个Pc类:

class Pc{

public $yanse;
public $pinbai;
public $xinghao;

function youxi(){
echo ‘玩游戏。。。。';
}
function shangwang(){
echo ‘上网。。。。';
}

function tingke(){
echo ‘听歌。。。。';
}

}

当属性和方法都定义好后,我们就生成对象来执行类里面的属性和方法了,我们通过new这个关键词+类名+()就可以生成一个对象

$xinmin_Pc=new Pc(); //这里生成一个对象xinmin_Pc(生成一台电脑对象)
$xinmin_Pc->yanse=’红色';//xinmin这个对象使用的类的属性是什么颜色,这里我们赋予“红色”值。
$xinmin_Pc->pinbai=’联想';//xinmin这个对象使用的类的属性是什么牌子,这里我们赋予“联想”值。
$xinmin_Pc->shangwang();//执行类Pc里的shangwang方法。

结果输出:“上网。。。。”shangwang这个方法执行完后的结果。

一个类可以实例化出N多个对象,我们只要通过实例货出来的对象执行类里面的方法就可以完成我们想要的工作了

通过Pc这个我们还可以实例化出另一个对象:

$zs_Pc=new Pc();
$zs_Pc->yanse=’红色'; //给属性赋值“红色”。
$zs_Pc->pinbai=’联想';//给属性赋值
$zs_Pc->tingke(); //执行类里的方法。

结果输出:“听歌。。。。”这样我们又可以得到一个对象执行tingke这个方法。

对象基础知识、对象的产生过程和内存分布、对象的释放.抽象.封装.继承.多态性需要注意一点的就是在定义类、类属性、类方法的时候,要有一个规范,这个规范就是在定义类名时头一个单词的字母要大写,而后如再出现有单词的话,单词的第一个字母大写其他全部小写;定义类属性时头一个单词的字母要小写,而后如再出现有单词的话,单词的第一个字母大写其他全部小写;定义类方法时和定义类属性一样。如:

class ArcChannel{ //类名:ArcChannel头一个单词的字母要大写,而后如再出现有单词的话,单词的第一个字母大写其他全部小写

public $arcChannelId; //定义类属性的规范。

function channelEidth (){ //定义类方法的规范。

}

} //只有这样的规范在团队开发时才方便别的程序员阅读与修改,还有就是要有在定义好类时要对这个类的功能做注释,这也是为了方便别的程序员阅读和日后自己的修改方便。

注:同时还需要注意一点就是类里的方法名都不能出现相同的名字(包括字母大小写不一样,但名称相同在内都不允许相同),这是PHP系统规定的,如果存在同名的方法就会报错

二、对象产生的过程及在内存中的分布情况

(1)、在我们来讲解对象产生过程之前,先来温习一下前面所学过的一些变量知识,即传址传值的应用与区别:http://blog.sina.com.cn/s/blog_8a6612910100wwb5.html。先用个例子再来加深对传址传值的理解。

$a=10;

$b=$a;

echo $b;

正常情况下,我们输出的$b的值就是$a的值10,因为这个情况是$b完全复制了$a的值,也就是相当于内存中又多出一个地址来存储$b复制$a过来的值。如果我们现在改变$a的值如下:

$a=10;

$b=$a;

$a=150;

echo $b;

改变$a=150后,再输出$b仍然是10,这就是传值方式,但是如果我们在$a前面加上&符时($b=&$a这样时):

$a=10;

$b=&$a;

$a=150;

echo $b;

这里再输出$b时发现$b的值也等于150了,这说明变量$a与$b同时指向内存中的一地址,这个地址在这个例子里就是$a所存储的值由原来的10改变为150这个内存地址值。

通过上面这个小例子,现在我们来看看对象在内存中是以什么方式(即:传址传值)存在的。先来举个例子:

class Ren{
public $xingming;
public $shenggao;
function suohua(){
echo’说话';
}
}
$xiaoming=new Ren();
$xiaoming->xingming=’小明';
$xiaoming->shenggao=’165CM';
echo $xiaoming->xingming.$xiaoming->shenggao;

在例子里,我们定义了一人Ren的类,属性有姓名($xingming)和身高($shenggao),方法是说话(suohua()),现在我们生成一个对象,这个对象叫“小明”,他的身高是“165CM” ,直接输出对象“小明165CM”得到的就是这个结果。那么结合上面的传址传值的例子来看,我们生成对象以后它返回的是什么?看下面例子:

class Ren{
public $xingming;
public $shenggao;
function suohua(){
echo’说话';
}
}
$xiaoming=new Ren();
$xm=new Ren(); //在前面例子里再生产一个对象,并让他们的发生相同。

$xiaoming->xingming=’小明';
$xiaoming->shenggao=’165CM';

$xm=$xiaoming;
$xiaoming->xingming=’张小明';//然后修改前一个生成的对象的一个发生,看看后生成的对象会有什么变化
echo $xm->xingming.$xm->shenggao;

通过输出的语句,得到结果是:“张小明165CM”从输出的结果看到是以传址的方式对对象进行了引用,按照前面传址传值的例子并没有加上&符,得到的结果就已经是引用的传址方式了,这就说明了,对象在它产生以后,返回的就是这个对象(变量)的一个引用地址,即传址所以我们不能把一个对象(变量)完完整整复制给另一个对象

对象基础知识、对象的产生过程和内存分布、对象的释放.抽象.封装.继承.多态性

通过上面的图片可以看到,对象在内存中的分布情况。

(2)、现在我们来看看对象的执行过程

1).在内存中开辟出对象的存储空间

2).执行构造方法

3).将对象的引用地址返回

举例:

class Ren{
public $xingming;
public $shenggao;
function __construct(){ //构造方法(构造函数),以后课程将讲到。
echo ‘一个人产生了!';
}
}
$Ren=new Ren(); //生成对象。

从对象的执行过程来看,对象开辟内存空间,然后就执行了构造方法,最后再返回对象的引用。这样我们就可以在构造方法里写一些配置的代码来完成一些初始化的操作。那么现在问题就来了,由于对象的引用是最后一步才完成的,那么如果我们想在对象被生成前修改对象属性怎样才完成呢?因为对象是最后一步才生成的,没有引用地址是无法修改到对象的属性的,那么怎么才完成对对象的属性进行修改呢?这时PHP为我们提供了$this这个关键词,$this是指当前对象的引用。来看看怎样通过$this修改对象的属性:

class Ren{
public $xingming;
public $shenggao;
function __construct($x,$s){
$this->xingming=$x; //通过当前对象引用$this关键词就可以在构造方法里先把属性修改为通过构造方法接收过来的参数。这就可以在没有生成对象之前就达到先修改对象属性的目的
$this->shenggao=$s;
}
}
$ligui=new Ren(‘李逵’,’180CM’);//通过最后生成的对象传入对象属性值到构造方法里。
echo $ligui->xingming.$ligui->shenggao;//就可以输出对象$Ren的值:“李逵180CM”。

我们再分析一下对象产生的流程:首先我们经过第一步给对象开辟内存的存储空间,然后选择构造方法,因为我们在内存中已经开辟给对象的存储空间,所以肯定有一个对象的存储地址,那么$this就可以得到我们这个当前对象的引用(换句话说,$this就存储我们当前对象的引用地址),然后我们就可以通过$this修改当前对象的属性等操作。如果有多个对象,这个$this保存就是本对象自己的引用

另外我们还可以通过调用里面的类(Ren)里的renMing()方法这样来操作得到的结果一样:“李逵0180CM

class Ren{
public $xingming;
public $shenggao;
function __construct($x,$s){
$this->xingming=$x;
$this->shenggao=$s;
}
function renMing(){
echo $this->xingming.$this->shenggao;
}
}
$Ren=new Ren(‘李逵’,’180CM’);
$Ren->renMing(); //执行类方法。

三、对象内存中的产生释放过程

我们在使用电脑的过程中,在使用每一个软件时都会在内存块里产生一个对象,这就是对象的产生。当对象产生后,它返回的就是这个对象的一个地址的引用,这样我们就可以通过这个引用来操作这个对象;然而对象的释放则是随着对象的产生后程序执行完整个代码页面时就把所有的对象释放掉,当然也可以通过unset()函数像删除一个变量一样删除一个对象。现在来看一下例子,先说说对象的产生过程。

class diansi{
public $yianse;
public $pinpai;
function __construct(){
$this->kan();//当前类对象的引用,它可以执行这个kan()函数。
}
function kan(){
echo “看电视”;
}
function __destruct(){

}
}
$d1=new diansi();//当编写好一个类后,我们就通过new关键词就可以创建好一个对象,这样一个对象就产生了,前面一节我们已经讲过__construct()这个构造函数,该函数是当我们创建对象后就会自动的去运行这个__construct()这个构造函数,这样我们也可以通过这个构造函数来对对象进行一些初始化操作,比如让它调用当前类里的其他成员函数等,在这个例子里就已经调用了$this->kan()函数去执行“看电视”的输出操作。通过输出我们可以看到,我们并没有调用类里的kan()这个函数,只是创建一个对象$d1,但“看电视”这个结果已经输出来了,这就我们构造函数__construct()已经在对象$d1创建后就先帮我们执行这个调用$this->kan()函数去执行了。

现在再来讲讲对象的释放过程:

还是看上面这个例子。

class diansi{
public $yianse;
public $pinpai;
function __construct(){
$this->kan();//当前类对象的引用,它可以执行这个kan()函数。
}
function kan(){
echo “看电视”;
}
function __destruct(){

echo “对象释放”;

}
}
$d1=new diansi();

例子的输出结果:

看电视
释放对象

通过输出结果我们看到,当一个页面代码执行完后,对象就被释放掉了,也就是从内存中删除掉了,__destruct()函数是用来释放对象的。当然也可以手动通过unset()函数来释放对象,因为使用unset()函数来手动的删除对象,所以在整个脚本代码没有执行完对象就已经被删除了,这样释放对象需要注意的就是必须完全删除所有引用对象的变量,这样对象才被完全释放掉,换句话说,如果对象引用仍然存在,那这人对象还在内存中存在。

如:

class diansi{
public $yianse;
public $pinpai;
function __construct(){
//$this->kan();
}
function kan(){
echo “看电视<br>”;
}
function __destruct(){
echo ‘释放对象';
}
}
$d1=new diansi();
$d2=$d1;
unset($d1);
echo ‘<br>=============================<br>';

输出结果:

=============================
释放对象

通过输出的结果我们看到。即使使用unset($d1)删除的对象$d1,但对象仍然还有个引用,所以并没有在一串 =============================前显示“释放对象”这个释放对象的标志,只有把$d2这个引用也删除了,这样对象才对释放掉。我们需要注意这点,但在日常开发中,我们使用PHP系统为我们提供的对象释放回收机智就够了,这样也不会出现错误。。

所以总结两点释放对象的情况:

(1)、我们脚本执行完成后释放对象

(2)、完全删除所有的对象引用后释放对象。

四、面向对象编程特性:抽象、封装、继承、多态

把一类对象的共同属性和方法抽象出来,形成类,这种思考方式就是抽象。

封装:把成员方法和成员属性封装到类中,隐藏属性和方法实现的细节,通过public(公有的)、protectde(私有的)、private、final、static限定类成员的访问权限,数据被保护在内部,只通过被授权的成员方法才可以操作,尽可能的对成员进行封装起来。

继承:可以使一个类继承并拥有另一个已经存在类的成员属性和方法,被继承的类称为父类或基类,继承类为子类。通过extends关键字实现继承关系。

来看看继承类的例子,通过一个文章操作类来详细解析继承类的使用过程:

class Arc{
function del($id){
echo “删除文章{$id}”;
}
function Edit($id){
echo “编辑文章{$id}”;
}
}
class arcInfo extends Arc{

}
class arcNews extends Arc{

}
$info=new arcInfo();
$info->del(100);//通过对象$info操作父类删除方法function del($id)输出结果:“删除文章100”。

我们通过创建一个父类Arc来对文章执行删除和编辑操作。因为文章系统里有许多分类的文章,如果都要重新写一个删除和编辑的代码来执行的话这样就太浪费资源的,这样我们就想到了继承父类的所有方法包括父类的构造方法也继承过来使用。

在这里我们分别创建两个类:arcInfo、arcNews这两个类都继承了父类Arc的所有功能。这样我们想删除或编辑谋个分类信息的内容时,直接传递一个文章ID参数过去就可以了,例子已经实现删除文章ID为100号的这编文章。

另外有一种情况是,由于父类所提供的函数、方法不够用,那么这个时候我们就要对父类的函数、方法进行重写,看下面例子:

class Arc{
function del($id){
echo “删除文章{$id}”;
}
function Edit($id){
echo “编辑文章{$id}”;
}
}
class arcInfo extends Arc{
function del($id){
echo “删除主表文章{$id}<br>”;
echo “删除附表文章{$id}”;
}
}//该类对父类的方法进行了重写。。
class arcNews extends Arc{

}
$info=new arcInfo();
$info->del(100);

对父类的方法进行重写后输出的结果:

删除主表文章100
删除附表文章100

因为大多数情况对文章系统操作时,都会涉及到主、附表的问题,如果父类里的方法没有写到删除附表文章的代码时,这时作为继续对象又要求有这个功能,那么我们就要对父类的方法进行了重写工作来完成我们想要的操作。注:子类对父类方法重写并不影响父类的方法,我们仍然可以正常调用父类的方法。

如:

class arcInfo extends Arc{
function del($id){
parent::del(100); //parent代表父类调用关键字
echo “<br>删除主表文章{$id}<br>”;
echo “删除附表文章{$id}”;
}
}

输出结果:

删除文章100 //从这里看到,父类方法并没有受到继承它的子类重写方法后有什么影响效果。
删除主表文章100
删除附表文章100

这就是我们面向对象特性的继续特性,注意:不能多层继承,如:class arcInfo extends Arc extends a这样的继承在PHP是无效的,PHP里只有单继承,但是后面我们会讲到,单继承多实现的功能

多态:子类继承父类,通过对父类方法重写实现多态;PHP没有像JSP那样纯正的多态,但不论是PHP还是JSP,多态的条件就是必须有继承。

多态的理解,就是多个子类继承父类的方法,并都对父类的方法进行了重写,这样就是PHP面向对象的多态性。