愤怒的大鸟 发表于 2015-2-3 23:30:05

PHP教程之探秘PHP 5的对象重载手艺

基础这个东西,有人问学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并流产法式的履行:

[*] <?php
[*]  class ThisWillFail {   
[*] public function foo() {   
[*]  return "Hello World!";   
[*] }   
[*]  }   
[*]  $class = new ThisWillFail;   
[*]  $class->bar();   
[*] ?>   
借助办法重载的匡助,代码可以捕捉到这类挪用且可以面子地赐与处置。属性重载与办法重载差不多。这类情形下,类把读/写操作重定向(亦可称代办署理)到类的属性,这些属性在类中没有显式界说。这里的专门办法是__set()和__get()。依附于毛病呈报品级,PHP翻译器凡是在存取一个不决义的属性时,或收回一个告诉,或推延一下并潜伏地界说这个变量。
而假如利用属性重载,翻译器却可以在设置一个不决义的属性时挪用__set(),而在存取一个不决义的属性值时挪用__get()。综上所述,使用重载手艺可以完成在象用PHP如许的静态言语停止时软件开辟工夫的大大延长。
2、延续性存储类举例
以下代码,经由过程利用属性重载手艺,用少于50行的PHP代码完成了下面所提到的延续性存储类。术语persistable意味着类可以从一个数据布局中描写一个元素,并坚持与底端存储体系的同步。用编码的注释就是,内部代码可使用类来完成从一个数据库表当选定一行。
如许,在法式运转时,可以直接存取类的属性来把持该行中的元素(读/取)。在剧本停止时,PHP将担任把更新的行数据回送到数据库中去。精心研读上面代码将有助于你了解甚么是属性重载。

[*] <?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办法以借助于办法重载的匡助来掌握类。上面咱们联合源代码停止剖析:

[*] <?php
[*]  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;   
[*]  }   
[*] }   
[*]  }   
[*]  $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   
[*] (   
[*] => Martin   
[*] => 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格式的写法,总是在这些方面出现问题,自己还总是找不到问题所在,这就提醒了自己,在写代码的时候一定要认真,不能粗心地老是少个“;”或者字母大小写不分,要不然很可能找半天都找不到错误。

金色的骷髅 发表于 2015-2-3 23:51:18

开发工具也会慢慢的更专业,每个公司的可能不一样,但是zend studio是个大伙都会用的。

老尸 发表于 2015-2-9 07:35:36

如果你可以写完像留言板这样的程序,那么你可以去一些别人的代码了,

冷月葬花魂 发表于 2015-2-27 04:31:08

我还是强烈建议自己搭建php环境。因为在搭建的过程中你会遇到一些问题,通过搜索或是看php手册解决问题后,你会更加深刻的理解它们的工作原理,了解到php配置文件中的一些选项设置。

爱飞 发表于 2015-3-6 15:22:06

实践是检验自己会不会的真理。

愤怒的大鸟 发表于 2015-3-13 03:09:43

没接触过框架的人,也不用害怕,其实框架就是一种命名规范及插件,学会一个框架其余的框架都很好上手的。

变相怪杰 发表于 2015-3-20 07:22:33

你很难利用原理去编写自己的代码。对于php来说,系统的学习我认为还是很重要的,当你有一定理解后,你可你针对某种效果研究,我想那时你不会只是复制代码的水平了。

第二个灵魂 发表于 2015-3-24 18:05:19

个人呢觉得,配wamp 最容易漏的一步就是忘了把$PHP$目录下的libmysql.dll拷贝到windows系统目录的system32目录下,还有重启apache。

若天明 发表于 2015-3-27 16:40:21

因为blog这样的可以让你接触更多要学的知识,可以接触用到类,模板,js ,ajax

精灵巫婆 发表于 2015-4-1 00:12:00

当留言板完成的时候,下步可以把做1个单人的blog程序,做为目标,

兰色精灵 发表于 2015-4-10 00:49:00

为了以后维护的方便最好是代码上都加上注释,“予人方便,自己方便”。此外开发文档什么的最好都弄齐全。我觉得这是程序员必备的素质。虽然会消耗点很多的时间。但是确实是非常有必要的。

莫相离 发表于 2015-4-11 01:11:03

其实没啥难的,多练习,练习写程序,真正的实践比看100遍都有用。不过要熟悉引擎

小女巫 发表于 2015-4-16 20:51:33

我要在声明一下:我是个菜鸟!!我对php这门优秀的语言也是知之甚少。但是我要在这里说一下php在网站开发中最常用的几个功能:

再现理想 发表于 2015-4-26 15:10:48

因为blog这样的可以让你接触更多要学的知识,可以接触用到类,模板,js ,ajax

谁可相欹 发表于 2015-4-29 16:56:18

刚开始安装php的时候,我图了个省事,把php的扩展全都打开啦(就是把php.ini 那一片 extension 前面的冒号全去掉啦),这样自然有好处,以后不用再需要什么功能再来打开。

不帅 发表于 2015-4-29 22:55:48

最后介绍一个代码出错,但是老找不到错误方法,就是 go to wc (囧),出去换换气没准回来就找到错误啦。

简单生活 发表于 2015-5-2 00:48:24

先学习php和mysql,还有css(html语言很简单)我认为现在的效果比以前的方法好。

灵魂腐蚀 发表于 2015-6-19 21:06:54

我学习了一段时间后,我发现效果并不好(估计是我自身的问题)。因为一个人的精力总是有限的,同时学习这么多,会导致每个的学习时间都得不到保证。

山那边是海 发表于 2015-7-1 16:49:11

学好程序语言,多些才是王道,写两个小时代码的作用绝对超过看一天书,这个我是深有体会(顺便还能练打字速度)。

分手快乐 发表于 2015-7-4 01:21:05

使用 jquery 等js框架的时候,要随时注意浏览器的更新情况,不然很容易发生框架不能使用。
页: [1] 2
查看完整版本: PHP教程之探秘PHP 5的对象重载手艺