魔术方法

来源:互联网 发布:js接受php时间戳 编辑:程序博客网 时间:2024/04/29 00:44
魔术方法(Magic methods)


PHP中把以两个下划线__开头的方法称为魔术方法,这些方法在PHP中充当了举足轻重的作用。 魔术方法包括:


__construct(),类的构造函数
__destruct(),类的析构函数
__call(),在对象中调用一个不可访问方法时调用
__callStatic(),用静态方式中调用一个不可访问方法时调用
__get(),获得一个类的成员变量时调用
__set(),设置一个类的成员变量时调用
__isset(),当对不可访问属性调用isset()或empty()时调用
__unset(),当对不可访问属性调用unset()时被调用。
__sleep(),执行serialize()时,先会调用这个函数
__wakeup(),执行unserialize()时,先会调用这个函数
__toString(),类被当成字符串时的回应方法
__invoke(),调用函数的方式调用一个对象时的回应方法
__set_state(),调用var_export()导出类时,此静态方法会被调用。
__clone(),当对象复制完成时调用
__construct()和__destruct()


构造函数和析构函数应该不陌生,他们在对象创建和消亡时被调用。例如我们需要打开一个文件,在对象创建时打开,对象消亡时关闭


<?php 
class FileRead
{
    protected $handle = NULL;


    function __construct(){
        $this->handle = fopen(...);
    }


    function __destruct(){
        fclose($this->handle);
    }
}
?>
这两个方法在继承时可以扩展,例如:


<?php 
class TmpFileRead extends FileRead
{
    function __construct(){
        parent::__construct();
    }


    function __destruct(){
        parent::__destruct();
    }
}
?>
__call()和__callStatic()


在对象中调用一个不可访问方法时会调用这两个方法,后者为静态方法。这两个方法我们在可变方法(Variable functions)调用中可能会用到。


<?php
class MethodTest 
{
    public function __call ($name, $arguments) {
        echo "Calling object method '$name' ". implode(', ', $arguments). "\n";
    }


    public static function __callStatic ($name, $arguments) {
        echo "Calling static method '$name' ". implode(', ', $arguments). "\n";
    }
}


$obj = new MethodTest;
$obj->runTest('in object context');
MethodTest::runTest('in static context');
?>
__get(),__set(),__isset()和__unset()


当get/set一个类的成员变量时调用这两个函数。例如我们将对象变量保存在另外一个数组中,而不是对象本身的成员变量


<?php 
class MethodTest
{
    private $data = array();


    public function __set($name, $value){
        $this->data[$name] = $value;
    }


    public function __get($name){
        if(array_key_exists($name, $this->data))
            return $this->data[$name];
        return NULL;
    }


    public function __isset($name){
        return isset($this->data[$name])
    }


    public function unset($name){
        unset($this->data[$name]);
    }
}
?>
__sleep()和__wakeup()


当我们在执行serialize()和unserialize()时,会先调用这两个函数。例如我们在序列化一个对象时,这个对象有一个数据库链接,想要在反序列化中恢复链接状态,则可以通过重构这两个函数来实现链接的恢复。例子如下:


<?php
class Connection 
{
    protected $link;
    private $server, $username, $password, $db;


    public function __construct($server, $username, $password, $db)
    {
        $this->server = $server;
        $this->username = $username;
        $this->password = $password;
        $this->db = $db;
        $this->connect();
    }


    private function connect()
    {
        $this->link = mysql_connect($this->server, $this->username, $this->password);
        mysql_select_db($this->db, $this->link);
    }


    public function __sleep()
    {
        return array('server', 'username', 'password', 'db');
    }


    public function __wakeup()
    {
        $this->connect();
    }
}
?>
__toString()


对象当成字符串时的回应方法。例如使用echo $obj;来输出一个对象


<?php
// Declare a simple class
class TestClass
{
    public function __toString() {
        return 'this is a object';
    }
}


$class = new TestClass();
echo $class;
?>
这个方法只能返回字符串,而且不可以在这个方法中抛出异常,否则会出现致命错误。


__invoke()


调用函数的方式调用一个对象时的回应方法。如下


<?php
class CallableClass 
{
    function __invoke() {
        echo 'this is a object';
    }
}
$obj = new CallableClass;
var_dump(is_callable($obj));
?>
__set_state()


调用var_export()导出类时,此静态方法会被调用。


<?php
class A
{
    public $var1;
    public $var2;


    public static function __set_state ($an_array) {
        $obj = new A;
        $obj->var1 = $an_array['var1'];
        $obj->var2 = $an_array['var2'];
        return $obj;
    }
}


$a = new A;
$a->var1 = 5;
$a->var2 = 'foo';
var_dump(var_export($a));
?>
__clone()


当对象复制完成时调用。例如在设计模式详解及PHP实现:单例模式一文中提到的单例模式实现方式,利用这个函数来防止对象被克隆。


<?php 
public class Singleton {
    private static $_instance = NULL;


    // 私有构造方法 
    private function __construct() {}


    public static function getInstance() {
        if (is_null(self::$_instance)) {
            self::$_instance = new Singleton();
        }
        return self::$_instance;
    }


    // 防止克隆实例
    public function __clone(){
        die('Clone is not allowed.' . E_USER_ERROR);
    }
}
?>
魔术常量(Magic constants)


PHP中的常量大部分都是不变的,但是有8个常量会随着他们所在代码位置的变化而变化,这8个常量被称为魔术常量。


__LINE__,文件中的当前行号
__FILE__,文件的完整路径和文件名
__DIR__,文件所在的目录
__FUNCTION__,函数名称
__CLASS__,类的名称
__TRAIT__,Trait的名字
__METHOD__,类的方法名
__NAMESPACE__,当前命名空间的名称
这些魔术常量常常被用于获得当前环境信息或者记录日志。








php内置变量了:DIRECTORY_SEPARATOR
DIRECTORY_SEPARATOR是一个返回跟操作系统相关的路径分隔符的php内置命令,在windows上返回/,而在linux或者类unix上反悔/,就是这么个区别,通常在定义包含文件路径或者上传保存目录的时候会用到。
PHP 把所有以 __ (两个下划线)开头的类方法当成魔术方法。所以你定义自己的类方法时,不要以 __ 为前缀。


1 、 __construct()
当实例化一个对象的时候,这个对象的构造方法将首先被调用;
我们知道 php5 对象模型和类名相同的函数是类的构造函数,那么如果同时定义构造函数和 __construc() 方法的话, php5 会默认调用 __contruct() 而不会调用同类名函数,所以 __contruct() 作为类的默认构造函数;


2 、 __destruct()
析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行。


3 、 __get(string $name)
当试图读取一个并不存在的属性时被调用;如果试图读取一个对象并不存在的属性的时候, php 就会给出错误的信息。如果在类里添加 __get 方法,并且我们可以用这个函数实现类似 java 中的反射的各种操作。


4 、 __set(string $name, mixed $value)
给未定义的变量赋值时将被调用


5 、 __call(string $name, array $arguments)
当调用一个不可访问方法(如未定义,或者不可见)时, __call() 会被调用。
__callStatic( string $name, array $arguments )
当在静态方法中调用一个不可访问方法(如未定义,或者不可见)时, __callStatic() 会被调用。


6 、 __toString()
当打印一个对象的时候被调用,这个方法类似于 java 的 toString 方法,当我们直接打印对象的时候回调这个函数。


7 、 __clone()
当对象被克隆时调用。


8 、 __sleep()
serialize() 函数会检查是否存在一个魔术方法 __sleep . 如果存在, __sleep() 方法会先被调用, 然后才执行序列化操作。这个功能可以用于清理对象,并返回一个包含对象中所有变量名称的数组。如果该方法不返回任何内容,则 NULL 被序列化,导致 一个 E_NOTICE 错误。 __sleep 方法常用于提交未提交的数据,或类似的操作。同时,如果你有一些很大的对象,不需要保存,这个功能就很好用。


9 、 __wakeup()
与 __sleep() 相反, unserialize() 会检查是否存在一个 __wakeup 方法。如果存在,则会先调用 __wakeup 方法,预先准备对象数据。 __wakeup 经常用在反序列化操作中,例如重新建立数据库连接,或执行其它初始化操作。


10 、 __isset()
当对未定义的变量调用 isset() 或 empty() 时, __isset() 会被调用。


11 、 __unset()
unset 一个对象的属性时被调用。如: unset($c->name) 。


12 、 __set_state()
调用 var_export 时,被调用。用 __set_state 的返回值做为 var_export 的返回值。


13 、 __autoload()
实例化一个对象时,如果对应的类不存在,则该方法被调用。简单的说就是类的自动加载 ; 当你尝试使用一个 PHP 没有组织到的类 , 它会寻找一个 __autoload 的全局函数 . 如果存在这个函数 ,PHP 会用一个参数来调用它 , 参数即类的名称。


14 、 __invoke()
当尝试以调用函数的方式调用一个对象时, __invoke 方法会被自动调用。


魔术常量 :
__LINE__ 文件中的当前行号。 
__FILE__ 文件的完整路径和文件名。如果用在被包含文件中,则返回被包含的文件名。自 PHP 4.0.2 起, __FILE__ 总是包含一个绝对路径(如果是符号连接,则是解析后的绝对路径),而在此之前的版本有时会包含一个相对路径。 
__DIR__ 文件所在的目录。如果用在被包括文件中,则返回被包括的文件所在的目录。它等价于 dirname(__FILE__) 。除非是根目录,否则目录中名不包括末尾的斜杠。( PHP 5.3.0 中新增) = 
__FUNCTION__ 函数名称( PHP 4.3.0 新加)。自 PHP 5 起本常量返回该函数被定义时的名字(区分大小写)。在 PHP 4 中该值总是小写字母的。 
__CLASS__ 类的名称( PHP 4.3.0 新加)。自 PHP 5 起本常量返回该类被定义时的名字(区分大小写)。在 PHP 4 中该值总是小写字母的。 
__METHOD__ 类的方法名( PHP 5.0.0 新加)。返回该方法被定义时的名字(区分大小写)。 
__NAMESPACE__ 当前命名空间的名称(大小写敏感)。这个常量是在编译时定义的( PHP 5.3.0 新增)
0 0