PHP 魔术方法
2016-01-24 21:22
726 查看
这个标题有点牵强因为php有不只9种魔术方法,但是这些将会引导你使用php魔术方法一个好的开始。它可能魔幻,但是并不需要魔杖。
这些'魔术'方法拥有者特殊的名字,以两个下划线开始,表示这些方法在php特定事件下将会被触发。这可能听起来有点自动魔法但是它真的很酷的,我们已经看过一个简单的例子在last
post,即我们使用一个构造器-使用这个作为我们第一个例子
构造器是一个魔术方法,当对象被实例化时它会被调用。在一个类声明时它常常是第一件做的事但是没得必要他也像其他任何方法在类中任何地方都可以声明,构造器也能像其他方法样继承。如果我们想到以前继承例子从介绍到oop,我们能添加构造方法到Animal类中,如:
现在我们创建一个类来继承Animal类-Penguin类!不添加任何属性和方法在Penguin类中,我们能申明并定义它继承自Animal类,如:
如果我们定义一个构造方法在Penguin类中,然后Penguin对象将会运行当它被实例化后。由于并没有构造方法,PHP会参考父类方法定义信息来使用它因此我们能覆盖父类方法,或者不,在我们的新类中-很便利。
你发现文件句柄也是构造器一部分吗?当我们使用完一个对象时真不想把事情放一边,因此析构方法做着与构造方法相反的事情。当对象被销毁时,析构方法会运行,或者明确的说当我们不再使用它时,php会为我们清理掉。Animal类中,我们的析构方法像这样,如:
析构器让我们关闭任何额外的资源比如被使用过的对象。在php中由于我们有这样运行时间短的脚本(留意在更新的php版本中增强的垃圾回收机制),通常讨论内存溢出根本不需要。然而它仍是好的推行方法来清理而且总体上让程序运行起来更高效。
这个魔术方法是一个非常灵巧的小技巧-它使实际上不存在的属性如同存在一半。让我们举个小企鹅的例子:
现在,如果我们的小企鹅有一个"name"属性,而在此之后加载的属性为"age",那么我们可以这样处理:
然而,设想一下,后端数据库或数据供应者发生了改变,"name"没有了,变味了"username"。并且设想这是一个非常复杂的应用,而需要修改的调用"name"的地方非常多。我们可以使用__get方法,使得"name"属性如同存在一样:
这并不是编写整个系统的好方法,因为它会让调试工作变得更困难,但它是一个非常有价值的工具。它允许如同属性一样使用或者展示需要经过计算的数据,以及无数我都想不到的地方。
那么,我们将所有对$this->name的调用都更改为返回$this->username的值,那么,如果我们想要设置这个值呢?也许我们有一个账户界面允许用户修改他们的名字。这时我们就需要__set方法的帮助了,举例说明:
这样,我们就针对大量的调用伪造对象的属性,正如我说的,这并不是一个正统的方法,但却是一个很有用的技巧,值得记住。
这里有两种近似的方法,我并没有单独列出来,而是一起说明。一个是_call方法,如果定义,它将在调用未定义过的方法时被调用;另一个是_callStatic方法,工作方式与第一个相同,但却是在调用未定义的静态方法时生效(PHP5.3加入).通常我使用__call进行友善的错误处理,这在需要别人整合调用你的方法的库代码中非常有用。例如,如果一段脚本拥有一个企鹅对象,名为$penguin,它包含一个$penguin->speak()方法...假设speak()方法没有定义,那么正常情况下我们会看到:
PHPFatalerror:CalltoundefinedmethodPenguin::speak()in...
通过定义__call方法,我们可以使用一些更友善的提示信息来代替PHP的错误提示:
这将捕获的错误并回应。在实际应用中,更合适的方法是依据你的需要纪录消息日志·,将用户重定向,或者抛出一个异常,但概念是相同的。在这里你可以处理任何你需要处理的不当调用,你可以检测方法的名称,并一一处理——例如,你可以同上面我们重命名属性一些样重命名方法。
__sleep()方法会被调用当对象被序列化后,并允许你处理序列化。这有各种各样的程序,一个很好的例子如果一个对象包含某种类型的指针,例如文件句柄或引用另一个对象。当对象被序列化然后解序列化,这些引用类型是无用的,因为这些类型的引用的目标可能不再存在或有效。因此,最好是来取消这些信息在存储它们之前。
__wakeup()是与__sleep()方法相反的,允许您更改对象解序列化的行为。和__sleep()一起使用,可以用来恢复被删除的句柄和对象当对象被序列化时。一个很好的例子程序是数据库句柄被取消设置当该项被序列化,然后恢复到当前配置中设置项目时,解序列化一个数据库句柄。
我们看过一个使用clone关键字的例子,在我的介绍从入门到oop的第二部分,创建对象的副本,而不是有两个变量指向同一个实际的数据。在一个类中重写此方法,我们可以观察发生了什么当在对象上使用clone关键字时,。虽然这是不是我们每一天能遇到的,一个漂亮的用例是创建一个真正的单例模式通过添加private访问修饰符给这个方法。
无疑把最好的始终留到最后,__toString方法是一个非常方便的附加方法对于我们的工具包。该方法可以声明覆盖对象的行为,当作为一个字符串输出时,例如,当它被输出时。如果你想能输出对象到模板中,你可以使用此方法来控制输出结果。让我们再来看看在Penguin类中:
在适当的位置,输出该对象通过调用echo输出它,如:
我不常常使用这种捷径,但是知道它的存在是很有用的。
更多可参考:http://www.php.net/manual/zh/language.oop5.magic.php
这些'魔术'方法拥有者特殊的名字,以两个下划线开始,表示这些方法在php特定事件下将会被触发。这可能听起来有点自动魔法但是它真的很酷的,我们已经看过一个简单的例子在last
post,即我们使用一个构造器-使用这个作为我们第一个例子
__construct
构造器是一个魔术方法,当对象被实例化时它会被调用。在一个类声明时它常常是第一件做的事但是没得必要他也像其他任何方法在类中任何地方都可以声明,构造器也能像其他方法样继承。如果我们想到以前继承例子从介绍到oop,我们能添加构造方法到Animal类中,如:1 | class Animal{ |
2 |
3 | public function __construct() { |
4 | $this ->created |
5 | $this ->logfile_handle fopen ( '/tmp/log.txt' , 'w' ); |
6 | } |
7 |
8 | } |
1 | class Penguin extends Animal { |
2 |
3 | } |
4 |
5 | $tux = new Penguin; |
6 | echo $tux ->created; |
__destruct
你发现文件句柄也是构造器一部分吗?当我们使用完一个对象时真不想把事情放一边,因此析构方法做着与构造方法相反的事情。当对象被销毁时,析构方法会运行,或者明确的说当我们不再使用它时,php会为我们清理掉。Animal类中,我们的析构方法像这样,如:01 | class Animal{ |
02 |
03 | public function __construct() { |
04 | $this ->created |
05 | $this ->logfile_handle fopen ( '/tmp/log.txt' , 'w' ); |
06 | } |
07 |
08 | public function __destruct() { |
09 | fclose( $this ->logfile_handle); |
10 | } |
11 | } |
__get
这个魔术方法是一个非常灵巧的小技巧-它使实际上不存在的属性如同存在一半。让我们举个小企鹅的例子:01 | class Penguin extends Animal { |
02 |
03 | public function __construct( $id ) { |
04 | $this ->getPenguinFromDb( $id ); |
05 | } |
06 |
07 | public function getPenguinFromDb( $id ) { |
08 | // |
09 | } |
10 | } |
1 | $tux = new Penguin(3); |
2 | echo $tux ->name " . $tux ->age " ; |
01 | class Penguin extends Animal { |
02 |
03 | public function __construct( $id ) { |
04 | $this ->getPenguinFromDb( $id ); |
05 | } |
06 |
07 | public function getPenguinFromDb( $id ) { |
08 | // |
09 | } |
10 |
11 | public function __get( $field ) { |
12 | if ( $field == 'name' ) { |
13 | return $this ->username; |
14 | } |
15 | } |
__set
那么,我们将所有对$this->name的调用都更改为返回$this->username的值,那么,如果我们想要设置这个值呢?也许我们有一个账户界面允许用户修改他们的名字。这时我们就需要__set方法的帮助了,举例说明:01 | class Penguin extends Animal { |
02 |
03 | public function __construct( $id ) { |
04 | $this ->getPenguinFromDb( $id ); |
05 | } |
06 |
07 | public function getPenguinFromDb( $id ) { |
08 | // |
09 | } |
10 |
11 | public function __get( $field ) { |
12 | if ( $field == 'name' ) { |
13 | return $this ->username; |
14 | } |
15 | } |
16 |
17 | public function __set( $field , $value ) { |
18 | if ( $field == 'name' ) { |
19 | $this ->username $value ; |
20 | } |
21 | } |
22 | } |
__call
这里有两种近似的方法,我并没有单独列出来,而是一起说明。一个是_call方法,如果定义,它将在调用未定义过的方法时被调用;另一个是_callStatic方法,工作方式与第一个相同,但却是在调用未定义的静态方法时生效(PHP5.3加入).通常我使用__call进行友善的错误处理,这在需要别人整合调用你的方法的库代码中非常有用。例如,如果一段脚本拥有一个企鹅对象,名为$penguin,它包含一个$penguin->speak()方法...假设speak()方法没有定义,那么正常情况下我们会看到:PHPFatalerror:CalltoundefinedmethodPenguin::speak()in...
通过定义__call方法,我们可以使用一些更友善的提示信息来代替PHP的错误提示:
01 | class Animal { |
02 | } |
03 | class Penguin extends Animal { |
04 |
05 | public function __construct( $id ) { |
06 | $this ->getPenguinFromDb( $id ); |
07 | } |
08 |
09 | public function getPenguinFromDb( $id ) { |
10 | // |
11 | } |
12 |
13 | public function __get( $field ) { |
14 | if ( $field == 'name' ) { |
15 | return $this ->username; |
16 | } |
17 | } |
18 |
19 | public function __set( $field , $value ) { |
20 | if ( $field == 'name' ) { |
21 | $this ->username $value ; |
22 | } |
23 | } |
24 |
25 | public function __call( $method , $args ) { |
26 | echo "unknown . $method ; |
27 | return false; |
28 | } |
29 | } |
__sleep
__sleep()方法会被调用当对象被序列化后,并允许你处理序列化。这有各种各样的程序,一个很好的例子如果一个对象包含某种类型的指针,例如文件句柄或引用另一个对象。当对象被序列化然后解序列化,这些引用类型是无用的,因为这些类型的引用的目标可能不再存在或有效。因此,最好是来取消这些信息在存储它们之前。
__wakeup
__wakeup()是与__sleep()方法相反的,允许您更改对象解序列化的行为。和__sleep()一起使用,可以用来恢复被删除的句柄和对象当对象被序列化时。一个很好的例子程序是数据库句柄被取消设置当该项被序列化,然后恢复到当前配置中设置项目时,解序列化一个数据库句柄。
__clone
我们看过一个使用clone关键字的例子,在我的介绍从入门到oop的第二部分,创建对象的副本,而不是有两个变量指向同一个实际的数据。在一个类中重写此方法,我们可以观察发生了什么当在对象上使用clone关键字时,。虽然这是不是我们每一天能遇到的,一个漂亮的用例是创建一个真正的单例模式通过添加private访问修饰符给这个方法。
__toString
无疑把最好的始终留到最后,__toString方法是一个非常方便的附加方法对于我们的工具包。该方法可以声明覆盖对象的行为,当作为一个字符串输出时,例如,当它被输出时。如果你想能输出对象到模板中,你可以使用此方法来控制输出结果。让我们再来看看在Penguin类中:01 | class Penguin { |
02 |
03 | public function __construct( $name ) { |
04 | $this ->species 'Penguin' ; |
05 | $this ->name $name ; |
06 | } |
07 |
08 | public function __toString() { |
09 | return $this ->name " (" . $this ->species ")\n" ; |
10 | } |
11 | } |
1 | $tux = new Penguin( 'tux' ); |
2 | echo $tux ; |
更多可参考:
相关文章推荐
- 一个关于if else容易迷惑的问题
- PHP5.2.*防止Hash冲突拒绝服务攻击的Patch
- 深入理解PHP之匿名函数
- JSP/PHP基于Ajax的分页功能实现
- 关于PHP通过PDO用中文条件查询MySQL的问题。
- 什么是设计模式
- PHP数据库长连接mysql_pconnect的细节
- Php Installing An Expansion
- PHP+Apache在Windows 9x下的安装和配置
- IIS 6 的 PHP 最佳配置方法
- 安装Apache和PHP的一些补充
- Linux Apache+MySQL+PHP
- 建立Apache+PHP+MySQL数据库驱动的动态网站
- PHP 5.3.0 安装分析心得
- apache 环境下 php 的配置注意事项
- ASP.NET、ASP、PHP、JSP之间有什么区别?
- PHP VBS JS 函数 对照表
- C语言实现的统计php代码行数功能源码(支持文件夹、多目录)
- php xml 入门学习资料