PHP魔法方法/函数详解

在php的语法中,有一些系统自带的方法名,均以双下划线开头,它会在特定的情况下被调用。即所谓的魔法函数。它们在面向对向编程中起着至关重要的作用。所以个人觉得很有必要整理一下。下面就php的15个魔法函数做一个详细整理:

1. __construct() 和 __destruct()

__construct() 对象初始化时会调用此方法(对于内核而言是指初始化完成后调用此方法).此方法用得比较多。__destruct() 当对象销毁时会调用此方法.那么什么时候对象会销毁呢?一是用户主动销毁对象,二是当程序结束时由引擎自动销毁

class People {

    protected $_alive;

    public function __construct()
    {
        $this->_alive = true; 
        echo 'Birth'.PHP_EOL;
    }

    public function __destruct()
    {
        $this->_alive = false;
        echo 'Die'.PHP_EOL;
    }
}

//主动销毁对象
$test = new Test();
unset($test);
sleep(1);

//程序完成后自动销毁对象
$test = new Test();
sleep(1);

2. __get() 和 __set()

面向对象编程中使用频率很高的两个方法.当设置和获取对象的属性不允许访问时性,此方法会被调用。一定注意是不存在或不允许被读写时才会被调用。
因此对于一个对象,其属性不确定时,用这两个方法效果很好。

__get($name) 获取对象不存在的属性或无法访问的属性时调用.$name表示要获取的属性名
__set($name, $value) 设置对象不存在的属性或无法访问的属性时调用.$name表示要设置的属性名,$value表示要设置的值.

//例如:我们可以构建一个不确定属性的数据记录类
class Record {

    protected $_data; 

    public function __get($name)
    {
        if (isset($this->_data[$name])) {
            return $this->_data;
        }
        return false;
    }

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

$record = new Record();
$record->name = 'andrew';
echo 'My name is '.$record->name.PHP_EOL;

3. __isset() 和 __unset()

这两个方法用得比较少些。当调用方法isset()判断对象是否存在某属性, 调用unset()注销某属性时。且当这些属性不存在或不可访问时,会分别调用__isset()和__unset()方法
与前面的__get()和__set()略同。都是某属性不存在或不可访问时被调用

__isset($name) 当调用方法isset()方法判断不可访问的类属性时调用.$name表示属性名.
__unset($name) 当调用方法unset()方法删除不可访问的类属性时调用.$name表示属性名.

//例如:
class People {

    public $name;

    public $sex;

    private $_age;

    public function __construct($name, $sex, $age)
    {
        $this->name = $name;
        $this->sex  = $sex;
        $this->_age = $age;
    }

    public function __isset($name)
    {
        echo 'The property '.$name.' not exists'.PHP_EOL;
    }

    public function __unset($name)
    {
        echo 'The property '.$name.' can not be unset'.PHP_EOL;
    }
}

$people = new People('andrew', 'male', 28);
isset($people->name);
isset($people->real_name);
unset($people->_age);

4. __call() 和 __callStatic()

前面,我们发现,在获取对象的属性时,如果此属性不存在会调用__get()方法。那么如果调用此对象的方法时,如果此方法不存在呢?php引擎会自动调用__call()方法。
同样,如果调用的是静态方法,且不存在时会调用__callStatic()方法。需要注意的是,__callStatic()使用时是一个静态方法,且仅在php5.3以上版本才支持.

__call($method, $args) 调用对象方法不存在或不允许被调用时此方法会被调用。$method表示调用的方法名,$args表示调用的参数
__callStatic($method, $args) 调用对象的静态方法不存在或不允许被调用时此方法会被调用。$method表示调用的方法名,$args表示调用的参数.

//例如:我们假定人只有跳走两种行为
class People {

    public function jump()
    {
        echo 'I can jump'.PHP_EOL;
    }

    public function walk()
    {
        echo 'I can walk'.PHP_EOL;
    }

    public function __call($method, $args)
    {
        echo 'I can not '.$method.PHP_EOL;
    }

    //此方法必须是静态方法,且在php5.3版本下可用
    public static function __callStatic($method, $args)
    {
        echo 'We can not'.$method.PHP_EOL;
    }
}

$people = new People();
$people->jump();
$people->walk();
$people->fly();
People::fly();

5. __sleep() 和 __wakeup()

这两个方法,咋一看,就是睡觉和唤醒嘛。那跟对象有什么关系?有时候该用的时候也想不起来。其实,我们简单点记,在php中有一个让对象睡觉的方法,叫searialize(),
它会将对象的各属性序列化以方便保存起来。而unsearialize()方法是将保存的序列化的数据解开变成对象。也叫唤醒。相对应的,当睡觉时,php会调用__sleep()方法,它
的返回值必须是一个数组,表示需要保存的属性项, 对于文件句柄,数据库连接等资源类型的数据是不能被序列化保存的。同理唤醒对象时,php会调用__wakeup()方法,
但与__sleep()不同的是,它返回值为空。被保存的属性都会被解开。那它有什么用呢?刚我们说了,searialize是不能保存资源的。那么唤醒时如果我们想用到这些资源怎么
办?回答很肯定,重新创建?那在哪里创建合适呢?当然是__wakeup()方法里面,因为每次唤醒时都会调用此方法嘛。这下我们很清楚这两个方法的用途了。

__sleep() 当调用searialize()方法时调用,返回值为数组,表示需要序列化的数据项.
__wakeup() 当调用unsearizlie()方法时调用。一般用来在唤醒时初始化资源对象.

//例如我们有一个用户类,用户名和性别都是类属性。用户的密码存在文件中
Class User {

    public $username;

    public $sex;

    public $passFile;

    private $_password;

    public function __construct($username, $sex, $passFile)
    {
        $this->username = $username;
        $this->sex      = $sex;
        $this->passFile = $passFile;
        $this->_password = file_get_contents($passFile);
    }

    public function getPassword()
    {
        return $this->_password;
    }

    public function __sleep()
    {
        return array(
            'username', 'sex', 'passFile',
        );
    }

    public function __wakeup()
    {
        $this->_password = file_get_contents($this->passFile);
    }
}

$user = new User('andrew', 'male', 'pass.data');
$serializeData =  serialize($user);
echo $serializeData.PHP_EOL;
$user = unserialize($serializeData);
echo $user->getPassword().PHP_EOL;

6. __toString()

当对象在需要转换成字符串时,会调用此方法。例如,echo对象时,将对象强制转换为string类型时, 用于字符串参数的函数中.注意:此方法的返回值必须为字符串。

//例如:
class Info {

    public function __toString()
    {
        return "info";
    }
}

$info = new Info();
echo $info.PHP_EOL;
echo md5($info).PHP_EOL;
echo (String) $info.PHP_EOL;
echo substr($info, 0, 2).PHP_EOL;

7. __clone()

此方法在复制对象时被调用。我们知道在php中.$a为一个对象,$b=$a时。$b为$a的引用。当$a发生改变时。$b也会随之发生变化。那么为了使$b不发生变化,我们需要用$b=clone $a;
那么,当$a在调用clone的时候,引擎会自动调用__clone()方法

//例如:以下一个简单的例子

class Data {

    public $value;

    public function __clone()
    {
        echo "Clone myself".PHP_EOL;
    }
}

$data = new Data();
$data->value = 4;
$newData = clone $data;
$data->value = 5;
echo "The data value is: ".$data->value.PHP_EOL;
echo "The new data value is: ".$newData->value.PHP_EOL;

//对面向对象比较熟的同学,一定对单例模式不陌生。PHP做单例模式的时候要记住把clone方法给禁掉。因为在单例模式中,是不允许复制对象的。如下例

class OnlyOne {

    //单例对象
    private static $_instance;

    //不允许外部和子类调用初始化方法
    private function __construct()
    {}

    //不允许复制
    public function __clone()
    {
        throw new Exception('Not allow to clone me');
    }

    //获取单例对象
    public static function getInstance()
    {
        if (self::$_instance != null) {
            return self::$_instance;
        }
        self::$_instance = new self();
        return self::$_instance;
    }
}

$onlyOne = OnlyOne::getInstance();
$newOne  = clone $onlyOne;

8. __autoload()

autoload顾名思义就是自动加载。它主要用来自动加载类。那如何自动加载呢?我们都知道在php中,要使用另外一个文件中的类需要用require或include方法
(包括require_once和include_one)导入进来。那么如果我要使用的类未被导入,则引擎会自动调用__autoload()方法。利用此特性,当我们的类名和类文件有规律
地存放时,我们可以使用__autoload()方法,根据需导入的类名,让程序自动导入文件。此函数在许多的MVC框架中起着重要的作用。
__autoload($name) $name表示需要自动导入的类名

//我们制订规则类名以目录名加下载线拼接而成。例如:类Model_Config_Xml表示Model/Config/Normal.php文件.我们如何实现自动加载
//有类文件Model/Config/Normal.php内包含类如下:
class Model_Config_Normal {

    public function __construct()
    {
        echo "Init Model_Config_Normal".PHP_EOL;
    }
}


function __autoload($name)
{
    $classPath = str_replace('_', DIRECTORY_SEPARATOR, $name);
    require_once("$classPath.php");
}

//此时将无需再require('Model/Config/Normal.php')
$config = new Model_Config_Normal();

9. __set_state()

这个方法用得不多。了解这个方法前,需要先知道var_export()函数,var_export()和var_dump()类似,输出一个变量的字符串表示。他与var_dump的区别在于它的返回结果的是合法的
php代码.此代码可以被eval执行. 注意:此方法是一个静态方法,且在php5.1以上版本才支持。

//例如:
class Test {

    public $name;

    public $age;

    public static function __set_state($data)
    {
        $obj = new Test();
        $obj->name = $data['name'];
        $obj->age  = $data['age'] + 1;
        return $obj;
    }
}

$test = new Test();
$test->name = 'andrew';
$test->age  = 27;
$code =var_export($test, true);
echo $code.PHP_EOL;
eval('$new='.$code.';');
var_dump($new);

10. __invoke()

这个方法我刚开始接触的时候,一眼望去,真看不出来它到底干嘛的。主要是不明白invoke是啥意思。后来查了字典才明白。意思是呼叫。英语差伤不起呀。
在php中这个方法用于,把对象当方法用的时候。此方法会被调用。很简单。注意,此方法仅5.3以上版本支持。

class Invoke {

    public function __invoke()
    {
        echo 'I can run'.PHP_EOL;
    }
}

$invoke = new Invoke();
$invoke();

转自:http://blog.csdn.net/inqihoo/article/details/9235103

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容