PHP开发者必须了解的9个魔术方法

转载 2018年04月03日 00:00:00

这些'魔术'方法拥有者特殊的名字,以两个下划线开始,表示这些方法在PHP特定事件下将会被触发。这可能听起来有点自动魔法但是它真的很酷的,我们已经看过一个简单的例子在 last post,即我们使用一个构造器-使用这个作为我们第一个例子。

  __construct

  构造器是一个魔术方法,当对象被实例化时它会被调用。在一个类声明时它常常是第一件做的事但是没得必要他也像其他任何方法在类中任何地方都可以声明,构造器也能像其他方法样继承。如果我们想到以前继承例子从介绍到oop,我们能添加构造方法到Animal 类中,如:

class Animal{

  
public function __construct() {
    
$this->created = time();
    
$this->logfile_handle = fopen('/tmp/log.txt', 'w');
  }

}

  现在我们创建一个类来继承Animal类 - Penguin类!不添加任何属性和方法在Penguin类中,我们能申明并定义它继承自Animal类,如:

class Penguin extends Animal {

}

$tux 
= new Penguin;
echo $tux
->created;

  如果我们定义一个构造方法在Penguin类中,然后Penguin对象将会运行当它被实例化后。由于并没有构造方法,PHP会参考父类方法定义 信息来使用它因此我们能覆盖父类方法,或者不,在我们的新类中-很便利。

  __destruct

  你发现文件句柄也是构造器一部分吗?当我们使用完一个对象时真不想把事情放一边,因此析构方法做着与构造方法相反的事情。当对象被销毁时,析构方法会运行,或者明确的说当我们不再使用它时,PHP会为我们清理掉。Animal类中,我们的析构方法像这样,如:

class Animal{

  
public function __construct() {
    
$this->created = time();
    
$this->logfile_handle = fopen('/tmp/log.txt', 'w');
  }

  
public function __destruct() {
    
fclose($this->logfile_handle);
  }
}

  析构器让我们关闭任何额外的资源比如被使用过的对象。在PHP中由于我们有这样运行时间短的脚本(留意在更新的PHP版本中增强的垃圾回收机制),通常讨论内存溢出根本不需要。然而它仍是好的推行方法来清理而且总体上让程序运行起来更高效。

  __get

  这个魔术方法是一个非常灵巧的小技巧 - 它使实际上不存在的属性如同存在一半。让我们举个小企鹅的例子:

class Penguin extends Animal {

  
public function __construct($id) {
    
$this->getPenguinFromDb($id);
  }

  
public function getPenguinFromDb($id) {
    
// elegant and robust database code goes here
  }
}

  现在,如果我们的小企鹅有一个 "name" 属性,而在此之后加载的属性为 "age",那么我们可以这样处理:

$tux = new Penguin(3);
echo $tux->name . " is " . $tux->age . " years old\n";

  然而,设想一下,后端数据库或数据供应者发生了改变,"name"没有了,变味了"username"。并且设想这是一个非常复杂的应用,而需要修改的调用"name"的地方非常多。我们可以使用 __get 方法,使得"name"属性如同存在一样:

class Penguin extends Animal {

  
public function __construct($id) {
    
$this->getPenguinFromDb($id);
  }

  
public function getPenguinFromDb($id) {
    
// elegant and robust database code goes here
  }

  
public function __get($field) {
    
if($field == 'name') {
      
return $this->username;
    }
}

  这并不是编写整个系统的好方法,因为它会让调试工作变得更困难,但它是一个非常有价值的工具。它允许如同属性一样使用或者展示需要经过计算的数据,以及无数我都想不到的地方。

__set

  那么,我们将所有对 $this->name 的调用都更改为返回 $this->username的值,那么,如果我们想要设置这个值呢?也许我们有一个账户界面允许用户修改他们的名字。这时我们就需要 __set 方法的帮助了,举例说明:

class Penguin extends Animal {

  
public function __construct($id) {
    
$this->getPenguinFromDb($id);
  }

  
public function getPenguinFromDb($id) {
    
// elegant and robust database code goes here
  }

  
public function __get($field) {
    
if($field == 'name') {
      
return $this->username;
    }
  }

  
public function __set($field, $value) {
    
if($field == 'name') {
      
$this->username = $value;
    }
  }
}

  这样,我们就针对大量的调用伪造对象的属性,正如我说的,这并不是一个正统的方法,但却是一个很有用的技巧,值得记住。

  __call

   这里有两种近似的方法,我并没有单独列出来,而是一起说明。一个是 _call 方法,如果定义,它将在调用未定义过的方法时被调用;另一个是 _callStatic 方法,工作方式与第一个相同,但却是在调用未定义的静态方法时生效(PHP 5.3 加入).通常我使用 __call 进行友善的错误处理,这在需要别人整合调用你的方法的库代码中非常有用。例如,如果一段脚本拥有一个企鹅对象,名为 $penguin ,它包含一个 $penguin->speak() 方法...假设 speak() 方法没有定义,那么正常情况下我们会看到:

  通过定义 __call 方法,我们可以使用一些更友善的提示信息来代替PHP的错误提示:

class Animal {
}
class Penguin extends Animal {

  
public function __construct($id) {
    
$this->getPenguinFromDb($id);
  }

  
public function getPenguinFromDb($id) {
    
// elegant and robust database code goes here
  }

  
public function __get($field) {
    
if($field == 'name') {
      
return $this->username;
    }
  }

  
public function __set($field, $value) {
    
if($field == 'name') {
      
$this->username = $value;
    }
  }

  
public function __call($method, $args) {
      
echo "unknown method " . $method;
      
return false;
  }
}

   这将捕获的错误并回应。在实际应用中,更合适的方法是依据你的需要纪录消息日志·,将用户重定向,或者抛出一个异常,但概念是相同的。在这里你可以处理 任何你需要处理的不当调用,你可以检测方法的名称,并一一处理——例如,你可以同上面我们重命名属性一些样重命名方法。

  __sleep

   __sleep()方法会被调用当对象被序列化后,并允许你处理序列化。这有各种各样的程序,一个很好的例子如果一个对象包含某种类型的指针,例如文件 句柄或引用另一个对象。当对象被序列化然后解序列化,这些引用类型是无用的,因为这些类型的引用的目标可能不再存在或有效。因此,最好是来取消这些信息在 存储它们之前。

  __wakeup

  __wakeup()是与__sleep()方法相反的,允许您更改 对象解序列化的行为。和__sleep()一起使用,可以用来恢复被删除的句柄和对象当对象被序列化时。一个很好的例子程序是数据库句柄被取消设置当该项 被序列化,然后恢复到当前配置中设置项目时,解序列化一个数据库句柄。

__clone

  我们看过一个使用clone关键字的例子,在我的介绍从入门到oop的第二部分,创建对象的副本, 而不是有两个变量指向同一个实际的数据。在一个类中重写此方法,我们可以观察发生了什么当在对象上使用clone关键字时,。虽然这是不是我们每一天能遇 到的,一个漂亮的用例是创建一个真正的单例模式通过添加private访问修饰符给这个方法。

  __toString

   无疑把最好的始终留到最后,__toString方法是一个非常方便的附加方法对于我们的工具包。该方法可以声明覆盖对象的行为,当作为一个字符串输出 时,例如,当它被输出时。如果你想能输出对象到模板中,你可以使用此方法来控制输出结果。让我们再来看看在Penguin类中:

class Penguin {

  
public function __construct($name) {
      
$this->species = 'Penguin';
      
$this->name = $name;
  }

  
public function __toString() {
      
return $this->name . " (" . $this->species . ")\n";
  }
}

  在适当的位置,输出该对象通过调用echo输出它,如:

$tux = new Penguin('tux');
echo $tux;

  我不常常使用这种捷径,但是知道它的存在是很有用的。

  更多魔术方法

  更多参考 http://php.net 列出的所有的魔术方法(是的,不仅仅是文中所列出的,我仅仅选出那些我认为最好开始学习的。)如果你想了解其他魔术方法,请仔细查看。

640?wx_fmt=png

PHP中的常见魔术方法功能作用及用法实例

概述 在面向对象编程中,PHP提供了一系列的魔术方法,这些魔术方法为编程提供了很多便利。PHP中的魔术方法通常以__(两个下划线)开始,并且不需要显示的调用而是由某种特定的条件出发。这篇文章简单...
  • a2534725767
  • a2534725767
  • 2017-02-15 12:57:30
  • 5501

开发人员需要掌握的HTML和CSS知识

作为一个软件开发人员,需要掌握的HTML和CSS的知识。
  • 2015年04月11日 21:54

总结2: PHP中的魔术方法及其应用场景

PHP中有一类特别的系统方法,它们统一以__开头,使用语义清晰简单,这类形式特殊、作用特殊的方法被称为魔术方法。常见的魔术方法有__construct()、__destruct()、__call()、...
  • hyh1123176978
  • hyh1123176978
  • 2016-11-11 18:18:06
  • 483

腾讯php面试题总结(一) 15个魔术方法的总结

腾讯php面试题总结(一)  PHP5中魔术方法函数有哪几个,请举例说明各自的用法   __wakeup   __construct, __destruct __call, __get, __s...
  • BossDarcy
  • BossDarcy
  • 2011-02-27 08:01:00
  • 3513

PHP 魔术方法之"__set()"和"__get"

__set()方法: 这个方法用来为私有成员属性设置值的,有两个参数,第一个参数为你要为设置值的属性名,第二个参数是要给属性设置的值,没有返回值。 这个方法同样不用我们手工去调用,它也可以做成私有...
  • u013372487
  • u013372487
  • 2015-07-02 10:36:29
  • 438

PHP中用魔术方法__autoload()实现类的自动加载

将一个独立的、完整的类保存到一个PHP页中,并且文件名和类名保持一致,这时每一个开发人员都需要养成的良好习惯。当引用多个类时使用include_once()和require_once()函数将类一个个...
  • manbujingxin
  • manbujingxin
  • 2011-07-31 19:54:49
  • 3474

php常见的几个魔术方法

1,__get和__set (1)这两个方法是为在类和他们的父类中没有声明的属性而设计的, __get( $property ) 当调用一个未定义的属性时访问此方法,这里的没有声明包括当使用对象调...
  • qq_34284638
  • qq_34284638
  • 2016-04-28 10:48:42
  • 731

PHP中十六个魔术方法详解

PHP中把以两个下划线__开头的方法称为魔术方法(Magic methods),这些方法在PHP中充当了举足轻重的作用。 魔术方法包括: 更多资料请访问:http://www.chinarobo...
  • xiaochao199404
  • xiaochao199404
  • 2016-12-04 19:56:33
  • 234

php 魔术方法__toString()的作用实例

php 魔术方法__toString()的作用实例
  • leyangjun
  • leyangjun
  • 2017-05-31 16:11:58
  • 645

php 魔术方法 __call

__call     PHP5 的对象新增了一个专用方法 __call(),这个方法用来监视一个对象中的其它方法。如果你试着调用一个对象中不存在的方法,__call 方法将会被自动调用。    F...
  • tashanhongye
  • tashanhongye
  • 2015-08-22 22:46:59
  • 477
收藏助手
不良信息举报
您举报文章:PHP开发者必须了解的9个魔术方法
举报原因:
原因补充:

(最多只允许输入30个字)