教学之友,学习之友。

站长教学网

当前位置: 站长教学网 > 网站编程 > PHP教程 >

PHP类中的魔术方法使用实例讲解

时间:2012-08-03 16:09来源:未知 作者:ken 点击:

PHP不知道为什么,钟爱“魔术”这个词,什么都弄魔术。其实想想也非常形象,就拿PHP中的魔术方法来说吧,你不需要去调用
他们的任何一个方法,他们却可以执行,影响你的程序。

在学习之前我要说两句,首先你不能漠视魔术方法,不要认为你不用这世界上用的人就非常少,作用就小。其实 PHP魔术方法PHP的一大特征,既然你学了一种语言,连它最基本的特征都没学,还叫学习了这个语言了吗?其次,不要认为看完我这篇文章就可以深入的 理解魔术方法了,我只是带您入门,以后的路还得您自己走。最后,腾讯曾经出了个面试题,就是关于魔术方法的,如果你学习完我这篇文章,应付这道题应该不成 问题了。还有一点,学习魔术方法一个最重要的地方就是学习它的用法,也就是它在什么情况下被调用。这是重点中的重点,请在下面的学习中注意这点。

首先学习PHP4中就有的魔术方法——__sleep()和__wakeup()。

其实这两个方法用的非常非常的少,少到在我接触PHP1年半的前提下,如果不去主动学习他们根本不知道他们的存在,但是本着对
学术严谨的态度,多学点没什么坏处,用不了多少时间,所以你也可以跟着我花几分钟的时间熟悉一下这两个方法。

我刚才说他们用的非常非常的少,我用了两个非常,大家可以想想一下他们的程度。不光我们要知道他们用的少,重要的是知道为
什么用的少。我先写一段代码,你看看你是否见到过或者曾经写过,我见识比较少,至少我之前是没有见过这么写的。

[php]
class Test {
        public $testStr;
        public function fun() {
                //搞点小事情
        }
}
$test = new Test();
echo serialize($test);  //输出  O:4:"Test":1:{s:7:"testStr";N;}
[/php]

它竟然把一个的给序列化了,也就是把一个转换成了一个字符串,可以传输或者保存下来。我以前可没有接触过这么神奇的事情。

下面我修改一下上面的代码,上面不是要搞点小事情吗?那我现在就搞给你看!

[php]
class Test {
        public $testStr;
        public function __construct($str) {
                $this->testStr = $str;
        }
}
$test = new Test("Skiyo.cn");
echo serialize($test);  //输出   O:4:"Test":1:{s:7:"testStr";s:8:"Skiyo.cn";}
[/php]

大家可以看到,$testStr被设置后,序列化后也对应了相应的值,但是现在有个问题,比如我这个变量是个秘密呢?而且我又得把这个序列化传给别的地方呢?
看下面的代码

[php]
class Test {
        public $mySecret;  //我的秘密不想让人知道
        public function __construct($secret) {
                $this->mySecret = $secret;
        }
}
$test = new Test("我的心里话  我爱某某某");
echo serialize($test);  //输出  O:4:"Test":1:{s:8:"mySecret";s:32:"我的心里话  我爱某某某";}
[/php]

大家可以看到,我的秘密序列化后还是存在的,可是我不想我的心里话被别人看到。这个时候PHP很贴心,她知道你的问题,所以设置了魔术方法

__sleep() 就表示当你执行serialize()这个序列化函数之前时的事情,就像一个回调函数,所以在这个回调函数里面我们就可以做点事情,来隐藏我的秘密。

[php]
class Test {
        public $mySecret;  //我的秘密不想让人知道
        public function __construct($secret) {
                $this->mySecret = $secret;
        }
        public function __sleep() {
                $this->mySecret = "你休想知道我的秘密!";
                return array('mySecret');  //一定要返回变量,不然返回的是个空,所以序列化也就没有东西了。
        }
}
$test = new Test("我的心里话  我爱某某某");
echo serialize($test);  //输出  O:4:"Test":1:{s:8:"mySecret";s:28:"你休想知道我的秘密!";}
[/php]

大家看到了吧?我的心里话被加密了,这个就是__sleep()的作用。至于__wakeup()和__sleep()大同小异,只不过是反序列化之前进行的回调函数。我不详细说了,大家看下下面的代码就明白了。

[php]
class Test {
        public $mySecret;  //我的秘密不想让人知道
        public function __construct($secret) {
                $this->mySecret = $secret;
        }
        public function __sleep() {
                $this->mySecret = "你休想知道我的秘密!";
                return array('mySecret');  //一定要返回变量,不然返回的是个空,所以序列化也就没有东西了。
        }
        public function __wakeup() {
                $this->mySecret = "我的秘密又回来了,哈哈!";
                //反序列化就不用返回数组了,就是对字符串的解密,字符串已经有了不用其他的了。
        }
}
$test = new Test("我的心里话  我爱某某某");
print_r(unserialize(serialize($test)));  //输出  Test Object ( [mySecret] => 我的秘密又回来了,哈哈! )
[/php]

到此为止我们的__sleep()和__wakeup()两个魔术函数就学习完毕了。

即使你曾经对魔术方法没有任何接触,经过上节课的学习,那么我相信你也对魔术方法有一定的了解了。有了上节课的基础,我们的学习将会非常简单,因为魔术方法都是大同小异的东西。

 

今天我们要学习的是四个非常有用的魔术方法:__set() __get() __isset() __unset() ,特别是其中的 __set() 和 __get() ,在以后的面向对象的编程中经常会遇到,所以也是我们今天的重点。

我们还是从一个代码的例子出手。我们先来按照Java中的思想写一个

[php]
class Test {

    //私有属性

    private $a;
        private $b;
        private $c;
        private $d;
        private $e;
        private $f;
        private $g;
        private $h;
        private $i;
        private $j;
    //还有很多很多....

    //Getters & Setters

        public function getA() {
                return $this->a;
        }

        public function getB() {
                return $this->b;
        }

        public function getC() {
                return $this->c;
        }

        public function getD() {
                return $this->d;
        }

        public function getE() {
                return $this->e;
        }

        public function getF() {
                return $this->f;
        }

        public function getG() {
                return $this->g;
        }

        public function getH() {
                return $this->h;
        }

        public function getI() {
                return $this->i;
        }

        public function getJ() {
                return $this->j;
        }

        public function setA($a) {
                $this->a = $a;
        }

        public function setB($b) {
                $this->b = $b;
        }

        public function setC($c) {
                $this->c = $c;
        }

        public function setD($d) {
                $this->d = $d;
        }

        public function setE($e) {
                $this->e = $e;
        }

        public function setF($f) {
                $this->f = $f;
        }

        public function setG($g) {
                $this->g = $g;
        }

        public function setH($h) {
                $this->h = $h;
        }

        public function setI($i) {
                $this->i = $i;
        }

        public function setJ($j) {
                $this->j = $j;
        }
    //还有很多很多...
}
[/php]

请不要认为我这是在凑字数,因为你得相信我,我没有稿费,所以不用故意拖这么多字数。

在一般的面向对象的编程中,这种情况是相当常见的,我曾经用Struts2写过一个音乐分享的网站,单单一个注册,因为注册要获取的字段很多,PHP 的$_POST,Struts2的机制就是给每个Form元素都设定一个Getter和Setter,这样下来,单单一个注册的就有多的数不清的 Getters和Setters。这是个非常艰巨的任务,程序员是写程序的,不是抄程序的,所以强大的Eclipse就为我们提供了一个简单的方法,只要 你设定了的属性,你就可以通过鼠标点击来生成相应的Getter和Setter,所以你不要认为上面的代码是我傻乎乎写的,我是个懒人,十分会偷懒 的:)

扯远了,PHP为了解决这个问题,而且又有魔术方法的基础,所以PHP创造了 __set() 和 __get() 。你只需要写一个方法,就可以代表上面大部分的Getters和Setters。

[php]
class Test {
        private $a;

        public function __set($key, $value) {  //必须是两个参数,第一个是属性,第二个是设置属性的值。
                $this->$key = $value;
                //这里不明白为什么是$this->$key ?? 一般不是这样写吗? $this->key ? 请看我下面的分解。
        }

        public function __get($key) {  //一个参数,要获得的属性
                return $this->$key;
        }
}
$test = new Test();
$test->__set('a', '我是A');  //给 属性a 设置一个值
echo $test->__get('a');  //打印a   输出  我是A
[/php]

通过上面的例子,我们就给A设置了一个值,并且打印了出来。

现在我来说上面为什么是$this->$key。这要说明白也是个不小的话题,PHP比较神奇,她可以设置一个变量的变量,什么意思呢?来看下面的例子。

[php]
$a = 'b';
$b = 'c';
echo $$a;  //输出c
[/php]

哇好神奇,竟然有连个$,好多的钱啊。下面我给你分解下。

[php]
$a = 'b';
$b = 'c';
echo ${$a};  //这样看的话是不是就明白多了呢? $a='b',所以大括号中就是b了,加上前面的$,就变成变量$b了。
[/php]

回到上面的类中,你可以注意到,$key只是我们需要传进来的一个内部属性,不是我们真正需要的,如果$this->key这样就会编程$key这 个属性的值了,而我们需要设置的是$this->a的值,所以这里就需要使用变量的变量了。明白了吗?有点绕,好好想想:)

经过这么折腾,我想你已经会一点 __get() 和 __set() 的使用方法了。但是上面的代码还不能用于实际的代码中,因为在实践中,往往内部属性的个数是不定的,你想到了什么解决办法?对,就是数组,PHP中数组的 长度是不定的,所以我们就可以给他无限增加元素。

[php]
class Test {
   public $values = array();  //存放属性的数组,以键值对的形式存在的。

   public function __get($name){
       return $this->values[$name];
   }

   public function __set($name, $value){
       $this->values[$name] = $value;
   }
}
$test = new Test();
$test->__set('a', '我是a');
$test->__set('b', '我是b');
echo $test->__get('a');  //输出  我是a
echo $test->__get('b');  //输出  我是b
[/php]

这样的话,如果是注册的页面,我们就可以灵活的获得和设置属性了。但是在实际运用中,我们知道传过来的值是不可靠的,我们得需要HTML转义,Mysql转义等等,所以我们可以写一个简单的回调函数,做数据验证的作用。

[php]
class Test {
   public $values = array();

   public function __get($name){
       return $this->values[$name];
   }

   public function __set($name, $value){
       $this->values[$name] = $this->validate($value);
   }
   private function validate($value){
       return htmlspecialchars(addslashes($value));
       //等等
   }
}
$test = new Test();
$test->__set('a', '<a>我是a</a>');
echo $test->__get('a');  //输出  &lt;a&gt;我是a&lt;/a&gt; 被转义啦...
[/php]

但是有的人不需要这样的,比如我前面提交的页面就有用户名和密码,不想再要别的了。当然,你如果用两个私有属性也可以解决,但是我说一下用一个数组的方法。

[php]
class Test {
        public $values = array('name' => '名字', 'passwd' => '密码');  //提前规定私有属性只有name和passwd

        public function __get($name){
                if (isset($this->values[$name])) {  //判断一下
                        return $this->values[$name];
                } else {
                        echo '没有此属性!';
                }
        }

        public function __set($name, $value){
                if (isset($this->values[$name])) {  //这里也判断一下
                        $this->values[$name] = $this->validate($value);
                } else {
                        echo '没有此属性!';
                }
        }
        private function validate($value){
                return htmlspecialchars(addslashes($value));
                //等等
        }
}
$test = new Test();
$test->__set('name', '<a>我是name</a>');  //设置name 无输出
$test->__set('我也不知道这个是什么', '<a>看看是我的值是多少</a>');  //输出 没有此属性!
echo $test->__get('name');  //输出  &lt;a&gt;我是a&lt;/a&gt;
echo $test->__get('随便看看');  //输出 没有此属性!
[/php]

到这里,我们算是基本掌握了 __set() 和 __get() 了,其实要学精通还是需要你自己去努力的,我只是带你入门而已。下面我们来看看 __isset() 和 __unset() 。

(责任编辑:ken)

TAG标签: php 魔术方法
顶一下
(2)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
注册登录:不允许匿名留言,登录后留言无需输入验证码。
栏目列表
最新内容