深入PHP面向对象、模式与实践——高级特性(4)
2017-03-21 21:48
651 查看
Final类和方法
final关键字可以终止类的继承。final类不能有子类,final方法不能被覆写。下面定义一个final类:
<?php final class Checkout { } class IllegalCheckout extends Checkout { } //将产生致命错误
如果只在Checkout中声明某个类方法为final,而不是将整个类声明为final,那么继承Checkout就不会出现致命错误。final关键字应该放在其他修饰词(例如protected或static)之前,如下所示:
<?php class Checkout { final public function totalize() { //计算账单 } } class IllegalCheckout extends Checkout { final public function totalize() { //修改账单计算方法 } } //将产生致命错误
使用拦截器
PHP提供了内置的拦截器(interceptor)方法,他可以“拦截”发送到未定义方法和属性的消息。它也被称为重载(overloading),但是自从这个术语在其他语言中被赋予了其他含义,我认为还是叫它拦截器好。PHP5支持3个内置的拦截器方法,当遇到合适的条件时就会被调用。__get()和__set()方法用于处理类(或其父类)中未声明的属性。当客户端代码试图访问未声明的属性时,__get()方法会被调用,并带一个包含要访问的属性名称的字符串参数。无论从__get()返回了什么,都会发给客户端代码,就好像带有该值的目标属性存在一样。下面是一个简单的例子:
class Person { public function __get($property) { $method = "get{$property}"; if (method_exists($this, $method)) { return $this->$method(); } } public function getName() { return "Bob"; } public function getAge() { return 44; } }
如果方法存在,就调用它并把它的返回值传递给客户。如果不存在,则什么也不做。用户试图访问的属性被解析为null。
__isset()方法和__get()类似。当客户在一个未定义的属性上调用isset()时,__isset()被调用。
class Person { private $_name; private $_age; public function __set($property, $value) { $method = "set{$property}"; if (method_exists($this, $method)) { return $this->$method($value); } } public function setName($name) { $this->_name = $name; if (!is_null($name)) { $this->_name = strtoupper($this->_name); } } public function setAge($name) { $this->_age = strtoupper($_age); } }
__unset()和__set()相对应。当unset()在一个未定义的属性上被调用时,__unset()会被调用,并以该属性的名称作为参数,然后你可以根据属性名进行必要的处理。
public function __unset($property) { $method = "set{$property}"; if (method_exists($this, $method)) { $this->$method(null); } }
__call()方法可能是最有用的拦截器方法。当客户端代码要调用类中未定义的方法时,__call()会被调用。__call()接受两个参数,一个是方法的名称,一个是传递给要调用方法的所有参数(数组)。__call()方法返回的任何值都会返回给客户,就好像调用一个真实存在的方法一样。__call()方法对于实现委托也很有用。委托是指一个对象转发或者委托一个请求给另一个对象,被委托的一方替原先对象处理请求。下面创建一个类将Person类的信息格式化并输出:
class PersonWriter { public function writeName(Person $p) { print $p->getName() . "\n"; } public function writeAge(Person $p) { print $p->getAge() . "\n"; } }
我们可以通过继承PersonWriter类以不同的方式输出Person类的信息。下面结合__call()和PersonWriter对象来实现Person类。
class Person { private $writer; public function __construct(PersonWriter $writer) { $this->writer = $writer; } public function __call($methodname, $args) { if (method_exists($this->writer, $methodname)) { return $this->writer->$methodname($this); } } public function FunctionName() { return "Bob"; } public function getAge() { return 44; } }
代码Person类接受一个PersonWriter对象作为构造方法的参数,并将它存储在属性变量$writer中。在__call()方法中,我们使用参数methodname,检查PersonWriter对象中是否存在同名的方法。如果相应的方法存在,我们就委托PersonWriter对象来处理对方法的调用,把当前类(Person)的实例作为参数传递给PersonWriter对象(使用伪变量)。这样我们就可以不用手动在Person类中调用如下委托方法:
function writeName(){ $this->writer->writeName($this); }
拦截器方法是非常有用的,但在使用时要慎重考虑,而且最好附上文档,清楚的说明代码的细节。
相关文章推荐
- 深入PHP面向对象、模式与实践——高级特性(2)
- 深入PHP面向对象、模式与实践——高级特性(5)
- 深入PHP面向对象、模式与实践——高级特性(1)
- 深入PHP面向对象、模式与实践——高级特性(6)
- 深入PHP面向对象、模式与实践——高级特性(3)
- 深入PHP面向对象、模式与实践——让面向对象编程更加灵活的模式(3)
- 深入PHP面向对象、模式与实践——组合模式
- PHP对象、模式与实践之高级特性分析
- php面向对象书籍推荐:深入PHP:面向对象、模式与实践(第3版)
- 深入PHP面向对象、模式与实践——执行及描述任务(3)
- 深入PHP面向对象、模式与实践——生成对象(2)
- 深入PHP面向对象、模式与实践——对象
- 深入PHP面向对象、模式与实践——对象工具(3)
- 《PHP对象、模式与实践》之高级特性
- 深入PHP面向对象、模式与实践——执行及描述任务(2)
- 深入php面向对象、模式与实践
- 深入PHP面向对象、模式与实践——生成对象(3)
- 深入php面向对象、模式与实践
- 深入PHP面向对象、模式与实践——执行及描述任务(1)
- 深入PHP面向对象、模式与实践——对象与设计