PHP面向对象 1.7 常见的魔术方法及应用

1. __clone()

该方法是在对象克隆时自动调用的,所以就可以通过此方法对克隆后的副本进行重新初始化。

__clone()方法不需要任何参数,该方法中自动包含$this$that两个对象的引用。$this是副本对象的引用,$that是原本对象的引用。

<?php

//声明一个Myclass类,在类中声明一个常量和一个成员方法
class MyClass
{
    const CONSTANT = 'CONSTANT VALUE';  //使用const声明一个常量并直接赋上初值;
    private $name;
    private $age;
    private $sex;

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

    function __clone()
    {
        $this->name = "我是" . $this->name . "的副本";
        $this->age = 100;
    }

    function say()
    {
        echo "我的名字:" . $this->name . ",性别:" . $this->sex . "年龄:" . $this->age;
    }
}

$class = new MyClass("chris", 20, '男');
$class2 = clone $class; //创建一个副本class2
$class->say();
$class2->say();

2. 类中通用的方法__toString()

“魔术”方法__toString()是快速获取对象的字符串表示的最简便方式,它是在直接输出对象引用时自动调用的方法。正常情况下如果直接输出对象的应用会报错:”Catchable fatal error:Object of class Person could not be converted to string”

如果在类中听添加了__toString() 方法,则直接输出 __toString方法返回的字符串,所以__toString()方法一定要有一个字符串作为返回值。通常在此方法中返回的字符串是使用对象中多个属性值链接而成的。

<?php

//声明一个Myclass类,在类中声明一个常量和一个成员方法
class TestClass
{
    private $foo;   //在类中声明一个成员方法

    function __construct($foo)
    {
        $this->foo = $foo;
    }

    public function __toString()
    {
        return $this->foo;
    }
}

$obj = new TestClass('Hello world!');
echo $obj;//直接输出__toString中的返回值Hello world!

3. __call()方法

调用对象中不存在的方法时会自动调用该方法,并且程序也会继续向下执行

需要两个参数:第一个参数是调用不存在的方法时,接收这个方法名称的字符串,而参数列表则以数组的形式传递到__call()方法的第二个参数中

魔术方法call的高级应用:连贯操作

<?php

class DB
{
    //声明一个私有成员属性组,主要是通过下表定义可以参加连贯操作的全部方法名称
    private $sql = array(
        "field" => "",
        "where" => "",
        "order" => "",
        "limit" => "",
        "group" => "",
        "having" => ""
    );


    //连贯操作调用field() where() ordre() limit() group() having()方法,组合sql语句
    function __call($methodName, $args)
    {
        //将第一个参数(代表不存方法的方法名称),全部转换成小写方式,获取方法名称
        $methodName = strtolower($methodName);
        //如果调用的方法名和成员属性数组$sql下标对应上,则将第二个参数给数组中下标对应的元素
        if (array_key_exists($methodName, $this->sql)) {
            $this->sql[$methodName] = $args[0];
        } else {
            echo '调用类' . get_class($this) . '中的方法' . $methodName . '()不存在';
        }
        //返回自己对象则可以继续调用本对象中的方法,形成连贯操作
        return $this;
    }

    //简单应用,没有实际意义,只是输出连贯操作后组合的一个sql语句,是连贯操作最后调用的一个方法
    function select()
    {
        echo "SELECT FROM {$this->sql['field']} user {$this->sql['where']} {$this->sql['order']}
        {$this->sql['limit']} {$this->sql['group']} {$this->sql['having']}";
    }
}

$db = new DB;
//连贯操作,也可以分为多行去连续调用多个方法
$db->field('sex,count(sex)')
    ->where('where sex("男","女")')
    ->group('group by sex')
    ->having('having avg(age)>25')
    ->select();
//如果调用的方法不存在,则
$db->query('SELECT * FROM user');

4.自动加载类__autoload()

__autoload()全局函数(不是在类中声明的函数)。如果存在这个函数,PHP会用一个参数来调用它,即类的名称。

/*这个例子中假设当前目录下每个文件对应一个类,当脚本尝试来创建一个类User()实例时,PHP会自动执行__autoload()函数,脚本假设user.class.php中定义有User类,不管调用时是大写还是小写,PHP将会返回名称的小写。。在组织定义类的文件名时一定要注意规则。*/
<?php
//声明一个自动加载类的魔术方法__autoload()
function __autoload($className)
{
    //在方法中使用include包含所在的文件
    include(strtolower($className) . ".class.php");
}

$obj = new User();  //User类不存在,则自动调用__autoload()函数,将类名"User"作为参数传入
$obj2 = new Shop(); //Shop类不存在则自动调用__autoload()函数,将类名"shop"作为参数传入

5. 对象串行化

对象会随着生成对象的程序的终止而终止,有时候需要将对象的状态记录下来,需要时再进行恢复。串行化就是把整个对象转化成为二进制字符串。

对象需要在网络中传输时,将对象串行化成二进制串后在网络中传输
对象需要持久保存时,将对象串行化写入文件或是数据库中
serialize()函数进行串行化一个对象,参数为对象的引用名,返回值为一个被串行化的字符串。
unserialize()函数进行反串行化,把串行化后的二进制字符串再转化为对象。

person.class.php

<?php
// 声明一个Person类,包含三个成员属性和一个成员方法
class Person{
    private $name;  //人的名字
    private $sex;   //人的性别
    private $age;   //人的年龄
    //构造方法为成员属性赋初值
    function __construct($name="",$sex="",$age=""){
        $this->name = $name;
        $this->sex = $sex;
        $this->age = $age;
    }
    //这个人可以说话的方法,说出自己的成员属性
    function say(){
        echo "我的名字:".$this->name.".性别:".$this->sex.",年龄:".$this->age."<br/>";
    }
}

serialize.php

<?php
require "person.class.php"; //在本文件中包含Person类所在的脚本文件
$person = new person("张三","男",20);	//通过person类创建一个对象,对象的引用名为$person
$person_string = serialize($person);   //进行串行化
file_put_contents("file.txt", $person_string); //将串行化后返回的字符串保存到file.txt文件中

unserialize.php

<?php
require "person.class.php"; //在本文件中包含Person类所在的脚本文件
$person_string = file_get_contents("file.txt");	//将file.txt文件中的字符串读出来并复制给变量$person_string
$person = unserialize($person_string);    //进行反串行化操作,形成对象$person
$person->say();    //调用对象中的say()方法,用来测试饭串行化的对象是否成功

6. __sleep()和__wakeup()

__sleep():在调用serialize()函数将对象串行化时,会自动调用对象中的__sleep()方法,用来将对象中的部分成员串行化。
__wake(): 在调用unserizlize()函数反串行化时会自动调用,用来在二进制串重新组成一个对象时,为新对象中的成员属性重新初始化。
__sleep()函数不需要接受任何参数,但需要返回一个数组,在数组中包含需要串行化的属性。未被包含在数组中的属性将在串行化时被忽略。如果没有___sleep()方法,则对象中的所有属性都将被串行化。

<?php
//声明一个Person类
class Person{
    private $name;
    private $sex;
    private $age;

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

    function say(){
        echo "我的名字:".$this->name.",性别:".$this->sex.".年龄:".$this->age."<br/>";
    }

    //在类中添加如此方法,在串行化时自动调用返回数组
    function __sleep(){
        $arr = array("name","age");	//数组中的成员$name 和$age 将被串行化,成员sex将被忽略
        return $arr;
    }

    //在反串行化对象时自动调用该方法,没有参数也没有返回值
    function __wakeup(){
        $this->age = 40;	//在重新组织对象时,为新对象中的$age属性重新赋值
    }
}

$person1  = new Person("张三","男",20);
//串行化,忽略属性sex
$person_string = serialize($person1);
echo $person_string."<br/>";
//反串行化对象,并自动调用__wakeup()方法重新为新对象$age赋值
$person2 = unserialize($person_string);    //反串行化后形成的对象$person2重新赋值$age = 40;
$person2->say();       //已经没有sex属性

结果

O:6:"Person":2:{s:12:"Personname";s:6:"张三";s:11:"Personage";i:20;}
我的名字:张三,性别:.年龄:40
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值