PHP V5.3 用延后静态绑定搞活面向对象编程

PHP V5.3 通过其延后静态绑定(LSB)特性解决了面向对象编程(OOP)的一些问题。了解 LSB 如何修复 PHP 的 OOP 编程问题以及如何实现需要使用 LSB 的一些众所周知的面向对象设计模式。
面向对象编程(OOP)可让开发人员通过使用数据抽象、封装、模块化、多态性和继承减少和简化代码 — 在对 OOP 有着深刻的理解的前提下。对 OOP 特性的了解还让 PHP 编码者得以利用设计模式 — 一些众所周知的用来解决常见问题的算法。PHP 自 V3.0 就已经提供了 OOP 功能,但直到 V5.3 到来时,PHP 的 OOP 实现内的怪异之处还是会阻止一些常见设计模式的使用。随着 PHP V5.3 的延后静态绑定(LSB)特性的出现,这些怪异之处均已彻底消失。

本文向您介绍了在 PHP V5.3 出现之前,存在问题的一些设计模式,解释了这些模式为何不能工作。然后展示了 PHP V5.3 的 LSB 特性,并给出了单例和活动记录设计模式。

重新回顾 OOP

如果您过去曾接触过 PHP OOP,那么很可能会出于以下原因而决定不使用它:

读过诸多宣称 PHP OOP 有问题的博文中的一条。

曾尝试实现一个简单的设计模式,但没有成功。

而对于 PHP V5.3,有关 OOP 的博文都是正面的,并且 PHP OOP 的问题在很大程度上已得到解决。是时候重回 PHP OOP 了。通过本文,您将看到在 V5.3 出现之前曾存在问题的一些设计模式:单例、生成器、工厂方法和活动记录。

单例、生成器和工厂方法设计模式被视为是 创建型 的模式,因它们可协助对象的构建。单例模式可能是最常用的 OOP 设计模式之一了 ;它限制了一个类的对象实例数只能为 1。比如数据库连接池就是单例设计模式的一个例子:我们一般不想让应用程序具有连接池类的多个资源密集型实例。

在需要分离复杂对象的构建和表示时,就需要用到生成器设计模式,您可以使用相同的构造过程来创建多个对象。生成器模式的实现可以很复杂,但一旦生成器可用,它就可以简化生成器所创建对象的构造和使用。具有输出 HTML、XML 或 PDF 能力的转变器就是需要使用生成器的一个例子。

而工厂方法模式,顾名思义,定义的是一个用来大量产出对象的方法的实现。您可以在应用程序需要创建其类型依赖于子类的实现的对象时,使用工厂方法模式。

活动记录模式则可用来在域类内包装关系数据库持久性方法。一个活动记录的每个实例都关系到数据库内的特定行。这个类包含了要插入、删除和更新数据库内的一行或多个行的方法。活动记录设计模式是由 Martin Fowler 在 Patterns of Enterprise Application Architecture 内定义的,并因在 Ruby on Rails 内的使用而日益流行。

前-LSB 的创建型设计模式实现问题

上述提到的所有这四个设计模式均使用了静态的属性和方法。例如,看一下清单 1 内所示的这个连接池单例。

清单 1. 一个简单的单例

<?php
class ConnPool {
private static $onlyOne;
private static $count = 0;
private function __construct() {
// real-world db conn stuff here...
}

public static function getInstance() {
if (!is_object(self::$onlyOne)) {
$klass = __CLASS__;
self::$onlyOne = new $klass();
self::$count++;
}
return self::$onlyOne;
}
public static function getInstanceCount() {return self::$count;}
}

$db = ConnPool::getInstance();
assert (1 == $db->getInstanceCount());
$db2 = ConnPool::getInstance();
assert (1 == $db2->getInstanceCount());
?>
请注意这个静态的 $onlyOne 变量。该变量被设计用来保存连接池对象的一个实例。$onlyOne 之前的静态修饰符将此变量关系到类本身。$onlyOne 变量是一个类属性,因为其作用域是这个类。而 $onlyOne 属性只有一个实例。当一个属性不具有静态修饰符时,就称其是一个对象属性,因为该属性对类的每个实例都是惟一的。

注意到 ConnPool 的构造函数方法(called __construct)是空的。在一个生产实现中,可以使用该方法来创建数据库连接池的间隔。

静态 getInstance 方法包含单例的模板代码。只有在静态的 $onlyOne 变量为空时,它才会创建一个 $onlyOne 实例。请注意它是如何使用 __CLASS__ 变量来获得类的类型并随即创建该类的一个实例的。

使用 getInstanceCount 方法只是为了证明只创建了连接池的一个实例。清单 1 底部的四行代码则证明无论请求 ConnPool 池类的一个实例多少次,它都会返回相同的对象。

所以, 到目前为止,此单例一切正常 — 直到您决定想要以面向对象的继承树的形式对这个连接池进行子类处理来支持多个数据库。清单 2 显示了这个继承树(为了清晰起见,删除了实例计数器和构造函数代码)。

清单 2. 在没有 LSB 时对单例进行的一次失败尝试

<?php
class ConnPool {
private static $onlyOne;
protected static $klass = __CLASS__;

public static function getInstance() {
if (!is_object(self::$onlyOne)) {
self::$onlyOne = new self::$klass();
}
return self::$onlyOne;
}
}

class ConnPoolAS400 extends ConnPool {
protected static $klass = __CLASS__;
}
$db = ConnPoolAS400::getInstance();
assert ('ConnPoolAS400' == get_class($db)); // fails
?>
为了支持多个类型的单例类,ConnPool 类添加了一个 $klass 静态变量并假设它会在子类中被覆盖。 ConnPoolAS400 子类扩展了 ConnPool 类并提供了 $klass 属性自己的版本。 我们的预期是当 ConnPoolAS400 类的实例创建时,$klass 属性会保存 ConnPoolAS400。但是当执行这些代码时,它不会按预期的那样运行。当 PHP 实用函数 get_class 返回 ConnPool 而不是 ConnPoolAS400 时,代码底部的声明会失败。 问题是 ConnPool 类的 getInstance 方法使用的是它自己的 $klass 属性版而非 ConnPoolAS400 的覆盖版。

时间: 2024-12-30 04:31:53

PHP V5.3 用延后静态绑定搞活面向对象编程的相关文章

泛函编程(11)-延后计算-lazy evaluation

     延后计算(lazy evaluation)是指将一个表达式的值计算向后拖延直到这个表达式真正被使用的时候.在讨论lazy-evaluation之前,先对泛函编程中比较特别的一个语言属性"计算时机"(strict-ness)做些介绍.strict-ness是指系统对一个表达式计算值的时间点模式:即时计算的(strict),或者延后计算的(non-strict or lazy).non-strict或者lazy的意思是在使用一个表达式时才对它进行计值.用个简单直观的例子说明吧:

php5.3后静态绑定用法详解_php技巧

本文实例讲述了php5.3后静态绑定用法.分享给大家供大家参考,具体如下: 手册原文: 自 PHP 5.3.0 起,PHP 增加了一个叫做后期静态绑定的功能,用于在继承范围内引用静态调用的类. 准确说,后期静态绑定工作原理是存储了在上一个"非转发调用"(non-forwarding call)的类名.当进行静态方法调用时,该类名即为明确指定的那个(通常在 :: 运算符左侧部分):当进行非静态方法调用时,即为该对象所属的类.所谓的"转发调用"(forwarding c

LDD3学习笔记(10):延时和延后

 1.延后执行 设备驱动常常需要延后一段时间来执行一个特定片段的代码,常常允许硬件完成某个任务. 2.时间管理 #include <linux/param.h> HZ  HZ 符号指定了每秒产生的时钟嘀哒的数目. #include <linux/jiffies.h> volatile unsigned long jiffies; u64 jiffies_64; jiffies_64 变量每个时钟嘀哒时被递增; 因此, 它是每秒递增 HZ 次. 内核代码几乎常常引用  jiffies

孙燕姿3天卖光所有备货专辑延后一周发行(图)

孙燕姿宣传照 孙燕姿造型成熟 新浪娱乐讯 华语乐坛天后孙燕姿,睽违四年的全新专辑<是时候>从2月14日情人节开始展开预购,短短3天时间,预购量爆冲,瞬间卖光了唱片公司原本预估整个预购期的数量,并且以惊人速度向上攀升.在考虑要让歌迷可以同步拿到赠品与专辑,唱片公司艰难的做下决定,将实体唱片上市日期推迟至3月8日,争取更长的时间制作承诺要给歌迷的赠品. 时隔四年再推新辑,孙燕姿在企划方面不但全程参与,宣传通告也坚持走自己的路线,秉持着不浮夸数字.不虚张声势等原则,希望大家把焦点放在音乐上讨论,就因

网友爆料:禁播变延后播出

中新网北京7月4日电(张曦) 将于7月6日在湖南卫视播出的电视剧<轩辕剑天之痕>(简称<轩辕剑>)将面临停播?昨日有网友爆料称广电总局已出台禁令,但从广电总局工作人员,到出品方和湖南卫视都表示没有得到确切消息,不少网友认为,这是一次"苦肉计"的炒作. 网友爆料:禁播变延后播出 <轩辕剑>改编自经典游戏<轩辕剑叁外传:天之痕>,于2011年5月15日开机.该剧讲述了陈国最后一位皇子陈靖仇的复国之路,最终,牺牲小爱成全大爱.该剧由胡歌.蒋劲夫

《最终幻想14》延后发售《DCUniverse》成首款PS3平台网游

根据美国购物网站亚马逊的近日发布的发货日期,索尼公司的超级英雄网游<DC Universe>或将在明年1月11日于PC和PS3平台上市. 根据国外媒体报道,订购了<DC Universe>的美国用户将从在线零售商处收到一份通知,通知称游戏将于1月18日至20日期间送达客户手中. 索尼在线娱乐的一位发言人表示,索尼公司将在48小时内对具体发售时间做出官方声明. 今年早些时候,索尼公司宣布<DC Universe>的发售日期从今年11月延后至明年.索尼在线娱乐老总John

索尼游戏网络未能如期修复或得延后到5月底

北京时间5月9日,据国外媒体报道,近期网络连连遭黑的索尼,现仍在架构新安全网络体系,防范未来类似攻击,因而未能赶上先前宣称的恢复PSN的游戏网络期限,让数百万名游戏玩家又度过一个无法连线的周末. 索尼周六宣布,索尼电子的2500名用户个人资料,遭黑客窃取并张贴在某处网站已经被删除.此些资料包含姓名或住址,但不包括个人信用卡资料. 索尼高层曾在5月1日表示,上周可以恢复部份网络服务,不过全面性的系统修复,可能得待到本月底.而对于详细时间进度和计划,公司发言人拒绝透漏. 公司在上周五,于博客发布文章

英国将2M宽带普及延后3年

本报讯 英国联合政府7月15日宣布,将把在全国实现两兆宽带部署的时间延后至2015年.这比英国之前提出的2012年的目标延后了3年.英国文化大臣 JeremyHunt说:"我支持全面普及最低两兆的宽带速率--上届政府提出到2012年实现这一目标,但我认为,依照上届政府的方案,他们没有为此准备足够的资金." 如今,Hunt重新为这项宽带普及计划设定了最后期限--2015年,到本届议会任期结束.他说:"在本届议会任期结束时,英国将拥有欧洲最高速的宽带网络,同时也是世界上最好的.&

远望谷董事长被抓余波:四项目延后月跌逾三成

张望 因董事长徐玉锁突然被检察机关"采取强制措施"引起广发关注的远望谷(002161.SZ),募投项目亦出现了延后. 12月4日,远望谷公告称,综合考虑市场环境.公司经营计划.项目实际进度及募投项目投资计划等因素,公司拟对非公开发行募投的四个项目达到预定可使用状态时间进行调整. 这四个募投项目分别是铁路车号智能跟踪装置.基于RFID的铁路车辆零部件管理系统.RFID手持机产品开发与应用和自助图书馆研发及产业化,共涉及募资43083.08万元,其预定可使用状态时间将从今年年底分别将延期1