|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
基础这个东西,有人问学php需要任何基础不? PHP 5中引入了对象重载手艺,本文将切磋关于办法__call(),__set()和__get()停止重载的能够性。在对重载实际作复杂引见后,咱们将经由过程两个例子直奔主题:第一例,完成延续存储类;第二例,找到一种完成静态的getter/setter的办法。
1、甚么是对象重载?
在PHP中谈到对象重载时,咱们要区分两品种型:
◆办法重载
◆属性重载
在办法重载的情形下,咱们要界说一个魔术般的办法__call(),它将完成一个在响应类中对不决义办法的笼统挪用。只要当你想存取类中不决义的办法时,这类笼统办法才会被挪用。在没无方法重载的情形下,上面的例子将招致PHP显示一条致命毛病信息:Call to undefined method ThisWillFail::bar() in/some/directory/example.php on line 9并流产法式的履行:
- class ThisWillFail {
- public function foo() {
- return "Hello World!";
- }
- }
- $class = new ThisWillFail;
- $class->bar();
- ?>
借助办法重载的匡助,代码可以捕捉到这类挪用且可以面子地赐与处置。属性重载与办法重载差不多。这类情形下,类把读/写操作重定向(亦可称代办署理)到类的属性,这些属性在类中没有显式界说。这里的专门办法是__set()和__get()。依附于毛病呈报品级,PHP翻译器凡是在存取一个不决义的属性时,或收回一个告诉,或推延一下并潜伏地界说这个变量。
而假如利用属性重载,翻译器却可以在设置一个不决义的属性时挪用__set(),而在存取一个不决义的属性值时挪用__get()。综上所述,使用重载手艺可以完成在象用PHP如许的静态言语停止时软件开辟工夫的大大延长。
2、延续性存储类举例
以下代码,经由过程利用属性重载手艺,用少于50行的PHP代码完成了下面所提到的延续性存储类。术语persistable意味着类可以从一个数据布局中描写一个元素,并坚持与底端存储体系的同步。用编码的注释就是,内部代码可使用类来完成从一个数据库表当选定一行。
如许,在法式运转时,可以直接存取类的属性来把持该行中的元素(读/取)。在剧本停止时,PHP将担任把更新的行数据回送到数据库中去。精心研读上面代码将有助于你了解甚么是属性重载。
- //装入PEAR的 <a href="http://pear.php.net/package/DB/">DB package</a>
- require_once "DB.php";
- class Persistable {
- private $data = array();
- private $table = "users";
- public function __construct($user) {
- $this->dbh = DB::Connect("mysql://user:password@localhost/database");
- $query = "SELECT id, name, email, country FROM " .
- $this->table . " WHERE name = ?";
- $this->data = $this->dbh->getRow($query, array($user),
- DB_FETCHMODE_ASSOC);
- }
- public function __get($member) {
- if (isset($this->data[$member])) {
- return $this->data[$member];
- }
- }
-
- public function __set($member, $value) {
- // dataset的ID是只读的
- if ($member == "id") {
- return;
- }
- if (isset($this->data[$member])) {
- $this->data[$member] = $value;
- }
- }
- public function __destruct() {
- $query = "UPDATE " . $this->table . " SET name = ?,
- email = ?, country = ? WHERE id = ?";
- $this->dbh->query($query, $this->name, $this->email,
- $this->country, $this->id);
- }
- }
- $class = new Persistable("Martin Jansen");
- $class->name = "John Doe";
- $class->country = "United States";
- $class->email = "john@example.com";
- ?>
你碰到的第一个成绩多是__construct(),这是PHP 5中引入的新的机关器办法。在PHP 4时期,机关器老是与它们的类名相婚配。在PHP 5中已不再是如许。你不需求对机关器办法有过量的懂得,除挪用它可以创立一个类的实破例;并注重到,这里利用了一个参数 - 履行一个基于此参数的数据库。此机关器把查询了局赋值给类属性$data。
接上去,法式界说了两个出格的办法__get()和__set()。你应当对它们早已熟习:__get()用于读取不决义的属性值,__set()用于修正不决义的属性值。
这意味着不管甚么时分从延续性存储类中读取/写入一个不决义的属性,由这些专门办法来担任办理在属性数组变量$data中的信息,而不是直接改动类的属性(切记:变量$data包括着来自于数据库中的一行!)。
类中的最初一个办法是__construct()的对峙者- 析构器__destruct()。PHP在"剧本封闭阶段"挪用析构器,典范地这是在PHP剧本履行将近停止的时分。析构器把来自于$data属性的信息写回到数据库中去。这恰是后面同步(synchronization )术语的寄义。
你能够早已注重到,这里的代码利用了PEAR的数据库笼统层包(database abstraction layer package)。其实这无所谓,经由过程其余体例与数据库通信也一样能申明本文的主题。
假如你仔细察看,会发明该延续性存储类的描写对照复杂。例子中仅触及了一个数据库表,而没有思索更庞杂的数据模子,如利用LEFT JOIN和其它庞杂的数据库操作手艺。但是你不用受此束缚,借助于属性重载,你可使用你本人幻想的数据库模子。只需求到场少量代码,你便可以在该延续性存储类中应用庞杂的数据库特征。
还存在一个小成绩 - 当在析构器中查询掉败时并没有引入毛病处置机制。是析构器的天分招致在这类情形下不成能显示响应的毛病信息,由于构建HTML标记经常在PHP挪用构析器之前就已停止了。
为处理这个成绩,你可以把__destruct()重定名为象saveData()如许的名字并在挪用剧本的某处手工履行这一办法。这关于类的延续性存储的概念并没有任何改动;仅是多写几行代码罢了。作为选择,你还可以在析构器中利用函数error_log()来纪录上司于体系局限的毛病纪录文件中的毛病信息。属性重载的任务机制就是如许。上面咱们会商一下办法重载。
3、办法重载举例
1. 静态的Getter/Setter办法
以下代码完成了"静态"getter/setter办法以借助于办法重载的匡助来掌握类。上面咱们联合源代码停止剖析:
- class DynamicGetterSetter {
- private $name = "Martin Jansen";
- private $starbucksdrink = "Caramel Cappuccino Swirl";
- func
- tion __call($method, $arguments) {
复制代码
- $prefix = strtolower(substr($method, 0, 3));
- $property = strtolower(substr($method, 3));
- if (empty($prefix) empty($property)) {
- return;
- }
- if ($prefix == "get" && isset($this->$property)) {
- return $this->$property;
- }
- if ($prefix == "set") {
- $this->$property = $arguments[0];
- }
- }
- }
- $class = new DynamicGetterSetter;
- echo "Name: " . $class->getName() . "\n";
- echo "Favourite Starbucks flavour: " . $class->getStarbucksDrink() . "\n\n";
- $class->setName("John Doe");
- $class->setStarbucksDrink("Classic Coffee");
- echo "Name: " . $class->getName() . "\n";
- echo "Favourite Starbucks flavour: " . $class->getStarbucksDrink() . "\n\n";
- ?>
很分明,这里的两个属性$name和$starbucksdrink都是公有的,就是说从类的内部是不克不及够存取这些属性的。在面向对象的编程中,完成公共的getter/setter办法来存取或修正非公共属性的值是很常常的工作。完成这些是单调的工作,且相当消耗工夫和精神。
借助于办法重载可以轻易得处理这个成绩。不是为每一个属性完成getter/setter办法,下面只完成了一个通用的__call()办法。这意味着当挪用一个不决义的getter/setter办法如setName()或getStarbucksdrink()时,PHP不会发生一个致命毛病而流产,而是履行(或代办署理到)魔术般的__call()办法。这是些复杂引见,上面咱们对__call()作一下深切剖析。
2. 具体剖析__call()办法
__call()的第一个参数是原始的且还没有肯定的办法(如setName),第二个参数是一个数字索引的一维数组,它包括了原始办法的一切参数。用两个参数("Martin"和42)挪用一个不决义的办法将发生上面数组:
- $class->thisMethodDoesNotExist("Martin", 42);
复制代码
- /导向__call()的第二个参数
- Array
- (
- [0] => Martin
- [1] => 42
- )
在办法__call()外部,假如原始办法以get或set开首,则要停止某种盘算以肯定是不是代码挪用的是一个getter/setter办法。并且,这类办法还要进一步剖析办法名的别的一构成局部(除去入手下手的三个字符),由于前面这局部字符串正代表getter/setter参照的属性的名字。
假如办法名中唆使有一个getter/setter,那末该办法或前往响应的属性值,或设置原始办法的第一个参数的值。假如没有的话,它不做任何工作,持续履行法式,好象没有工作产生。
3. 完成方针
本色上,响应于恣意的属性,存在一种办法答应代码静态地挪用恣意的getter/setter办法,这类算法是存在的。这在短时间内开辟一个法式原型的情形下是很便利的:不是消费大批工夫来完成getters/setters,开辟人员可以专注于建模API并包管使用法式的基本准确。把__call()办法归入到一个笼统类中乃至有能够使你在未来的PHP工程开辟中完成代码的重用!
4. 缺乏以外
有长处就出缺点。以上办法也有几个缺乏:较大些的项目可以会利用象phpDocumentor如许的东西来跟踪API布局。用下面引见的静态办法,一切的getter/setter办法固然不会呈现在主动生成的文档中,这是无需多作注释的。
别的一个缺乏是,类里面的代码可以存取类内的每个公有属性。当利用真实的getter/setter办法时,有能够区分开内部代码可以存取的公有属性和对类内部不成见的"真实的"公有属性 - 由于咱们无方法重载,并且有虚拟的getter和setter办法可以使用。
结论
本文经由过程两个例仔细致剖析了PHP 5中对象重载的两种情况。很但愿本文的办法匡助你进步PHP编程的任务效力!同时,你也应苏醒地看到这类办法的缺乏。
刚开始因为习惯于ASP格式的写法,总是在这些方面出现问题,自己还总是找不到问题所在,这就提醒了自己,在写代码的时候一定要认真,不能粗心地老是少个“;”或者字母大小写不分,要不然很可能找半天都找不到错误。 |
|