无忧岛

15 七, 2010

php面向对象OOP编程教程(七) – 类的特殊方法

Posted by: kinglife In: php

这些特殊方法你也可以叫它们做特殊函数,因为我们前面说过了,方法就是类里面的函数。实际上前面我们已经玩过两个特殊方法了,还记得吗?就是构造方法析构方法,即__construct__destruct这两个方法。那么希望大家记住,PHP类里面凡是以双下划线开头的方法,都有特殊作用,并且都会自动执行

今天我们就来玩另外四个特殊方法,它们分别是:__set()__get()__isset()__unset()

大家注意,之前因为还没有讲到这些特殊方法,同时也是为了方便演示,很多代码中属性都是用默认的public作为声明的,既然现在我们开始玩这些新知识了,那么在此声明,我们不建议将属性声明为默认的public

一般情况下,直接从类的外部访问和设置属性是个很糟糕的想法,因为我们说过了,OOP的优点是封装,而且鼓励使用封装,因此我们在声明属性的时候,应该使用privateprotected,这更符合OOP的编程思想和现实的逻辑。但是,很多情况下我们仍然需要访问和设置属性,而且是经常性的,于是PHP为我们提供了两个方法,用__get()访问属性,用__set()设置属性

我们先通过代码来看看它们是怎么用的,然后再来分析,请结合注释仔细看:

class Role //角色类
{
    //属性部分
    private $role_name; //封装:角色的名字
    private $role_sex; //封装:角色的性别
    private $role_skill; //封装:角色的技能

    //方法部分
    private function __get($attribute_name) //允许访问属性(有一个参数:传入属性的名称)
    {
        if($attribute_name == 'role_name' || $attribute_name == 'role_sex') //如果是:名字、性别
        {
            return $this->$attribute_name; //就允许访问
        }
    }
       
    private function __set($attribute_name,$attribute_value) //允许设置属性(有两个参数:传入属性的名称和值)
    {
        if($attribute_name == 'role_name' || $attribute_name == 'role_sex') //如果是:名字、性别
        {
            $this->$attribute_name = $attribute_value; //就允许设置
        }
    }
}

//将角色类实例化得到一个对象
$brother_chun = new Role();

//设置属性
$brother_chun->role_name = '春哥'; //可以设置:姓名
$brother_chun->role_sex = '男'; //可以设置:性别
$brother_chun->role_skill = '霸气菊花残'; //无法设置:技能

//访问属性
echo $brother_chun->role_name.'<br />'; //可以访问:姓名
echo $brother_chun->role_sex.'<br />'; //可以访问:性别
echo $brother_chun->role_skill.'<br />'; //无法访问:技能

不要看到代码就烦哦,我刚学编程的时候也是这样,这是个坏习惯,因为无论你的理论基础有多么的扎实,如果看不懂代码那也是白搭,更不要说去写了。养成分析代码的好习惯,尤其是去看别人写的优秀的代码,那样会使自己进步非常快。

注意:这里参数是带$号的,关于这个问题貌似“PHP圣经”又写错了几个例子,在此提醒大家,请与属性做好区别。

参数:$this->$something
属性:$this->something

__get()方法用于访问属性,当我们试图访问一个属性的时候,它会自动将属性的名称作为参数传入,并且返回属性的值。
__set()方法用于设置属性,当我们试图设置一个属性的时候,它会自动将属性的名称和值作为参数传入并执行设置操作,没有返回值。

通过运行代码我们会发现,虽然所有属性都被声明为private,即封装私有属性,但是通过__get()方法和__set()方法,我们可以允许某些属性(姓名、性别)能够被访问或设置,并且可以定制一些个性化的条件控制属性的访问和设置,比如我们只允许把性别设置成“男”或“女”,而不能设置为“人妖”等等。如果我们删除这两个特殊方法,试图直接访问或设置属性,那么程序就会报错。

好,那么这两个特殊方法就玩到这里,请大家多看代码和注释,并且尝试修改程序,通过这种方式来进一步了解它们。

下面玩__isset()__unset()这两个特殊方法,我们在原有代码的基础上新增几行代码:

class Role //角色类
{
    //属性部分
    private $role_name; //封装:角色的名字
    private $role_sex; //封装:角色的性别
    private $role_skill; //封装:角色的技能

    //方法部分
    private function __get($attribute_name) //允许访问属性(有一个参数:传入属性的名称)
    {
        if($attribute_name == 'role_name' || $attribute_name == 'role_sex') //如果是:名字、性别
        {
            return $this->$attribute_name; //就允许访问
        }
    }
       
    private function __set($attribute_name,$attribute_value) //允许设置属性(有两个参数:传入属性的名称和值)
    {
        if($attribute_name == 'role_name' || $attribute_name == 'role_sex') //如果是:名字、性别
        {
            $this->$attribute_name = $attribute_value; //就允许设置
        }
    }
    //新增部分
    private function __isset($attribute_name) //检测属性是否设置(有一个参数:传入属性的名称)
    {
        return $this->$attribute_name; //返回结果
    }
       
    private function __unset($attribute_name) //删除属性(有一个参数:传入属性的名称)
    {
        unset($this->$attribute_name); //进行删除
    }
}

//将角色类实例化得到一个对象
$brother_chun = new Role();

//设置属性
$brother_chun->role_name = '春哥'; //可以设置:姓名
$brother_chun->role_sex = '男'; //可以设置:性别
$brother_chun->role_skill = '霸气菊花残'; //无法设置:技能

//访问属性
echo $brother_chun->role_name.'<br />'; //可以访问:姓名
echo $brother_chun->role_sex.'<br />'; //可以访问:性别
echo $brother_chun->role_skill.'<br />'; //无法访问:技能

//新增部分
echo var_dump(isset($brother_chun->role_name)); //检测并输出变量是否被设置
unset($brother_chun->role_name); //删除此属性
echo $brother_chun->role_name.'<br />'; //由于属性被删除,因此没有输出

__isset()__unset()这两个特殊方法的原理和__get()和set()方法的原理是一样的,即将属性作为参数传入,并在类的内部进行处理。说白了,这两个特殊方法就是为了方便在属性被封装的情况下,允许在类的外部使用isset()和unset()这两个PHP函数,更多的也没有什么好说的了,大家看代码和注释吧,尝试着修改运行看看,OK,今天就玩到这里。

作者:hetty 首发地址:http://www.im286.com/thread-4823948-1-1.html

版权所有,转载时必须以链接形式注明作者和原始出处及本声明:KingLife@无忧岛

本文链接: http://www.islandcn.com/post/778.html



No Responses to "php面向对象OOP编程教程(七) – 类的特殊方法"

Comment Form

Flickr PhotoStream

    flickrRSS probably needs to be setup

About

Name:KingLife
Email:lifewz#163.com