最近在看《深入php:面向对象、模式与实践》这本书,php里专门讲解面向对象的书籍不多,讲解设计模式和实际代码实践的书籍就更少了,但是少不代表质量不好,本书就是值得阅读的一本。这里借用thinkphp 麦苗当儿的座右铭:每多学一点知识,就少写一行代码。希望大家都能多抽些时间来看书,然后工作的更加轻松也更快乐~~~
下面进入正题,先来看一个问题,我们在项目里经常封装类来实现指定的业务逻辑,比如下面的Memebr类:
class Member { protected $name; protected $age; function __construct($name,$age){ $this->name=$name; $this->age=$age; } //登陆 public function login($name,$pwd){ if(!$info=M('Member')->where(array('name'=>$name,'pwd'=>$pwd))->find()){ return false; }elseif($info['status']==0){ return false; } //具体登陆操作... return true; } }
Member类很简单,每个会员有姓名和年龄属性,然后还有一个登陆的方法,那么现在重点在登陆方法,我们在控制器里调用会员的login方法可以实现登陆与否的检测,但是问题在于当登陆失败后我们不知道具体的失败原因,因为程序只返回布尔类型的判断,于是聪明的程序员可以这样更改login:
//登陆 public function login($name,$pwd){ if(!$info=M('Member')->where(array('name'=>$name,'pwd'=>$pwd))->find()){ return array('status'=>0,'info'=>'用户不存在'); } elseif($info['status']==0){ return array('status'=>0,'info'=>'用户被禁用'); } //具体登陆操作... return true; }
这样传递数组就可以解决问题了,控制器里可以获取错误信息了,不过你可能就会说这样太繁琐了,返回数组写好多代码,且最大问题是每个人可能返回各自数组命名,这样就不能统一而导致代码混乱了,混乱是不可取的。于是聪明的程序员就想到了我们现在使用面向对象,那就要用对象的思想来解决,于是我们这样来写:
class Member { protected $name; protected $age; public $error;//错误信息 function __construct($name,$age){ $this->name=$name; $this->age=$age; } //登陆 public function login($name,$pwd){ if(!$info=M('Member')->where(array('name'=>$name,'pwd'=>$pwd))->find()){ $this->error='用户不存在'; return false; }elseif($info['status']==0){ $this->error='用户已被禁用'; return false; } //具体登陆操作... return true; } }
我们给Member类添加一个错误的属性,来存放错误信息,这样控制器里就可以直接实例化获取error错误信息,但是呢,就像人一样,我们每个人都有属于自己的属性,比如姓名、年龄、存款等等,我们不会轻易随便就透露这些信息,只有当别人问起的时候我们才考虑要不要告诉他们,类里的属性也是一样的,我们会把属性尽可能的保护起来,这里我们就需要把Member类型的属性error改成protected类型的,方便子类和自己使用,那你要问了,那调用者怎么调用呢,这样我们就会约定好属性固定的getter和setter方法,如下面代码
class Member { protected $name; protected $age; protected $error;//错误信息 function __construct($name,$age){ $this->name=$name; $this->age=$age; } //获取名字的getter public function getName(){ return $this->name; } //获取错误信息的getter public function getError(){ return $this->error; } //登陆 public function login($name,$pwd){ if(!$info=M('Member')->where(array('name'=>$name,'pwd'=>$pwd))->find()){ $this->error='用户不存在'; return false; } elseif($info['status']==0){ $this->error='用户已被禁用'; return false; } //具体登陆操作... return true; } }
这样我们就可以解决了,如果想要告诉别人某个属性那么我们就给它添加它的getter方法,不过挑剔的程序员肯定又会说了,我只是想要调取一个属性却要调取它的getter方法好烦呢,而且如果有一天你换了一种风格的getter方法是不是就需要修改控制器里的调取方法了。那怎么办呢?聪明的程序员发现了php中存在神奇的魔术方法,还不了解的童鞋可以去手册里看看,于是就有了下面的版本:
class Member { protected $name; protected $age; protected $error;//错误信息 function __construct($name,$age){ $this->name=$name; $this->age=$age; } //获取名字的getter public function getName(){ return $this->name; } //获取错误信息的getter public function getError(){ return $this->error; } //__get魔术方法,访问未定义属性是调用 public function __get($property){ $method = 'get'.ucfirst($property); if(method_exists($this,$method)) return $this->$method(); } }
我们添加类的一个__get魔术方法来拦截用户调用未定义或者受保护的属性,然后由这个魔术方法来调用我们的getter方法,这样前面控制器里就能直接调用受保护的属性了。当然,对于检测错误最好的方式还是使用php的异常功能即抛出一个特定的异常,这个我们到后面再来补充说明吧。
这男主跟IS 精灵使的剑舞的男主一样的设定。。