PHP 面向对象编程之魔术方法

1. 克隆对象;

  • 有时可能需要根据一个对象完全克隆出一个一模一样的对象,而且克隆以后,两个对象互不干扰。
# 格式

$obj = new Class();
$objcopy = clone $obj;

# 魔术方法:__clone() 
# 当执行 clone 克隆时会自动调用的魔术方法,主要用于解决对象中特殊属性的复制操作
# 也就是修改一些特殊的成员属性的值

  • 实例:demo.class.php
<?php

class demo{

    public $name;
    public $age;

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

    public function say(){
        echo "say " . $this -> name;
    }

    // __clone() 魔术方法,是在克隆对象时被自动调用的
    // 作用:可以对新对象的成员属性进行赋值
    public function __clone(){
        $this -> name = "lisi";
        $this -> age = 20;
    }
}

$demo = new demo("zhangsan", 18);
$demo -> say();

$demo1 = clone $demo;

echo "<hr />";
$demo1 -> say();
var_dump($demo1);

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

  • 魔术方法 __toString() 是快速获取对象的字符串表示的最快捷方式。即当我们直接要输出一个对象时,如echo $a; print $a;,那么会自动调用的此魔术方法。
  • 注意:__toString() 方法必须返回一个字符串类型的值。
  • 实例:demo.class.php
<?php
class demo{

    public $name;

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

    // 魔术方法 __toString(),是直接 echo 或 print 对象时被自动调用
    // 作用:可以直接返回字符串(有内容的字符串或空字符串)或用于调用流程处理
    public function __toString(){
        $this -> d();
        $this -> e();
        return '';
    }

    private function d(){
        echo "d....";
    }

    private function e(){
        echo "e...";
    }
}

$demo = new demo("zhangsan");
echo $demo;		// 输出:d....e...

3. __invoke() 方法的运用;

  • 魔术方法 __invoke() 当我们把一个对象当函数执行时,那么会自动调用此魔术方法。
  • 实例:demo.class.php
<?php
class demo{

    public function __invoke($param){
    	$this -> d();
        $this -> e();
        return $param;
    }

    private function d(){
        echo "d....";
    }

    private function e(){
        echo "e...";
    }
}

$demo = new demo();
echo $demo('zhangsan');		// 输出: d....e...zhangsan

4. __call() 方法的运用;

  • 当试图调用一个对象中不存在的方法时,就会产生错误。
  • PHP提供了 __call() 这个方法来处理这种情况。即当调用一个不可访问方法(如未定义,或者不可见)时,__call() 会被调用。
# 格式

mixed __call(string $name, array $arguments)

# 说明
# 第一个参数:$name 表示方法名
# 第二个参数:$arguments 表示调用时的参数列表(数组格式)

  • 实例1:db.class.php
  • 调用不存在的方法,自动加载魔术方法 __call()
<?php
class db{
	
	 // 魔术方法 __call() 是在调用 一个不存在的方法时被自动调用
     // 第一个参数:调用的方法名
     // 第二个参数:调用方法时传的参数列表(数组格式)
	 public function __call($methodName, $args){
        echo "你所调用的方法{$methodName}(),参数:";
        print_r($args);
        echo "不存在!";
    } 

}

$db = new db();
$db->select();

  • 实例2:db.class.php
  • 实际项目中经常用 __call() 方法对成员属性进行赋值操作
<?php
class db{

	// 声明了一个成员属性,是一个数组,数组的下标都是sql语句的各个变化的部分
	// 用魔术方法 __call() 对这些下标赋值
    private $sql = [
    		"table" => '',
            "field" => '*',
            "where" => '',
            "order" => '',
            "limit" => ''
    ];

	public function __call($methodName, $args){
		// # 操作1
		// # 执行 $db->table("user"),$methodName 会把 "table" 传进来,$args[0] 会得到 "user"
		// $this -> sql[$methodName] = $args[0];

		// 操作2
		// $this 代表本对象,和`db()`是等价的
		// 在调用`table()`方法的时候就自动调用了 __call() 方法
		// __call() 方法有一个返回值,返回 $this,那`$db -> table("user")`就相当于 $this
		// 而 $this 又和 $db 等价,`$db -> table("user")` 相当于 $db,它是对象
		$this -> sql[$methodName] = $args[0];
		
		// 返回本对象,为了实现连惯操作
		return $this}

	public function select(){

	}

}

$db = new db();
// 操作1解释:
// $db->table("user");
// var_dump($db);	// 此时成员属性 sql 的下标 "table" 会赋值成 "user"

// 操作2解释:
// 如果修改成下面的代码运行会报错,因为`$db`是对象环境,但是`$db -> table("user")`不是
// 此时需要实现**连贯操作**
// 我们要访问对象中的成员方法,必须是有对象+对象运算符+方法,那只要把`$db -> table("user")`变成对象就行
// (具体代码、解释看上面)
// 总结:使用连贯操作,调用不存在的方法,但是用不存在的方法,可以把我们的成员属性进行连续的赋值
// 如果不用这种方法,你要写 table()方法、field()方法、limit()方法等等,类里面需要写太多的方法了。
// 现在用只需要写一个 __call() 魔术方法,然后所有的都能进行赋值
$db -> table("user") -> field("id,username,pwd") -> limit(0,10) -> order("id DESC") -> where("id > 5");
var_dump($db);

// 当然如果需要查询数据库,还需要一个 select() 方法,这个方法必须存在了,因为是执行查询语句的
// 往下看实例3
  • 实例3:db.class.php
<?php
class db{
	
    private $sql = [
    		"table" => '',
            "field" => '*',
            "where" => '',
            "order" => '',
            "limit" => ''
    ];
    // 魔术方法 __call() 是在调用 一个不存在的方法时被自动调用
    // 第一个参数:调用的方法名
    // 第二个参数:调用方法时传的参数列表(数组格式)
    /*
    public function __call($methodName, $args){
        echo "你所调用的方法{$methodName}(),参数:";
        print_r($args);
        echo "不存在!";
    } 
     */ 

    public function __call($methodName, $args){
        // 判断调用的方法名是否是**成员属性数组的下标**
        if(array_key_exists($methodName,$this-> sql)){
            // 如果是就进行赋值操作
            $this -> sql[$methodName] = $args[0];
        }else{
            // 如果不是就给出提示信息
            die("你所调用的方法{$methodName}()不存在!");
        }

        // 返回本对象,为了实现连惯操作
        return $this;
    } 

    public function select(){
        if($this -> sql['where']){
            $where = "WHERE {$this -> sql['where']}";
        }

        if($this -> sql['order']){
            $order = "ORDER {$this -> sql['order']}";
        }

        if($this -> sql['limit']){
            $limit = "LIMIT {$this -> sql['limit']}";
        }
        $sql = "SELECT {$this->sql['field']} FROM {$this -> sql['table']} {$where} {$order} {$limit}";
        echo $sql;
    }

}


$db = new db();
// sql语句随着赋值而产生变化,相当于封装了一个 db 类
// 每条 sql 语句都有一些固定的部分,这样每次就不用重写 sql 语句,只需要按照规则去调用方法
// 最终实现拼接好的语句,用 MySQL 去执行一下,就会获取结果集
$db -> table("user") -> field("id,username,pwd") -> where("id <100") -> select();
var_dump($db);

5. 自动加载类;

  • PHP5 中当 new 实例化一个不存在的类时,则自动调用此函数__autoload(),并将类名作为参数传入此函数。可以使用这个实现类的自动加载。
  • autoload 是一个比较特殊的魔术方法,他也叫函数,它写在类的外部,是可以独立存在的。
  • 实例: autoload.php
<?php
// __autoload() 是在实例化对象时,如果类不存在就会被自动调用
// 参数:实例化的类名
// 作用:可以用于自动引入类文件

function __autoload($className){
   	// 注意:类文件名要有规律
    //      类文件名要与类名统一的部分
    //      类文件的路径要有规律
    $file = $className . ".class.php";
    $path = "./class/" . $file;

    if(file_exists($path)){
        include($path);
    }else{
        die("你调用使用的{$className}.class.php 文件不存在");
    }
}

$demo = new demo();
var_dump($demo);
$demo1 = new demo1();

./class/demo.class.php

<?php
class demo{

}

6. 对象串行化。

  • 串行化和反串行化
    • 串行化是一个函数,它不但可以把对象串行化,也可以把数组串行化
    • 为什么要串行化?因为对象和数组是不能直接存储的(写进数据库或者文本文档),也不能直接通过网络传输
    • 网络传输走的是 HTTP 协议,主要传输的是字符串。
    • 数组或者对象只能装成字符串,然后再进行之后的操作,这个函数就是提供这个功能
<?php
// 实例
$arr = ["name"=>"zhangsan", "age"=>18, "gender"=>"female"];
$str = serialize($arr);
var_dump($str);
// 返回
// string(73) "a:3:{s:4:"name";s:8:"zhangsan";s:3:"age";i:18;s:6:"gender";s:6:"female";}"
// a 表示 array、3 表示有三个值,s 表示 string、4 表示4个长度
$arr1 = unserialize($str);
var_dump($arr1);

  • 魔术方法 __sleep() 和魔术方法 __wakeup()

    • 分别在串行化和反串行化时被自动调用
  • 实例:demo.class.php

<?php
class demo{
    
    public $name;
    public $age;
    public $sex;

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

    // 魔术方法__sleep() 是在串行化对象时被自动调用
    // 控制哪些成员属性可以被串行化
    public function __sleep(){
        // 返回一个数组,数组的值就是要串行化的成员属性
       return ["name", "gender", "age"];
    }

    // 魔术方法 __wakeup() 是在反串行化对象被自动调用
    public function __wakeup(){
        // 可以把发生改变的成员属性进行重新的赋值操作
        $this->age = $this -> age + 1;
    }
}

/*
$demo = new demo("lisi",20,"male");
$str = serialize($demo);

// 串行化,可以串行化数组也可以串行化对象,串行化对象时只是串行化了成员属性,不能串行成员方法
// O:4:"demo":3:{s:4:"name";s:4:"lisi";s:6:"gender";s:4:"male";s:3:"age";i:20;}
// O 代表 object,4 代表 demo 类名的长度,3 代表对象有3个成员属性
$handle = fopen("./data.txt","w+");
fwrite($handle, $str);
fclose($handle);
var_dump($str);
*/

实例:unserialize.php

<?php
include("./demo.class.php");
$str = file_get_contents("./data.txt");
$d = unserialize($str); //可以把串行化的结果进行反串行化操作
var_dump($d->age);

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 魔术方法是Python中的特殊方法,它们以双下划线开头和结尾,例如__init__、__str__、__add__等。这些方法可以在的实例化、运算符重载、属性访问等方面提供特殊的行为。 __init__方法是一个特殊的构造函数,用于初始化的实例。__str__方法用于返回对象的字符串表示形式,可以通过print函数输出。__add__方法用于重载加法运算符,可以实现自定义的加法操作。其他常用的魔术方法还包括__eq__、__lt__、__gt__等,用于比较运算符的重载。 学习魔术方法可以让我们更好地理解Python面向对象编程的特性,提高代码的可读性和可维护性。 ### 回答2: 魔术方法是Python中最有趣且也是最强大的概念之一。魔术方法(也称为特殊方法或双下划线方法)是一些特殊的方法,它们以双下划线(__)开头和结尾,并具有特定的名称。 这些特殊方法可以为我们提供许多有用的功能,例如重载操作符,处理的属性,实现自定义迭代器,使用描述符等。 下面是一些常见的魔术方法: __init__:这是最常见的魔术方法。当创建一个实例时,它会被自动调用。它用于初始化对象的属性。 __str__:当你想要将一个对象转换成字符串时,这个方法会被调用。如果你不指定__str__方法,Python默认会使用对象名和内存地址来表示对象。 __repr__:这个方法和__str__方法似,也是用于将对象转换成字符串。但是__repr__方法在调试时有很大的作用,因为它返回的字符串可以用来唯一地标识对象。 __len__:这个方法可以返回对象的长度。例如,如果你想获取一个字符串的长度,你可以使用len("hello"),在底层,它实际上是调用了字符串对象的__len__方法。 __getattr__和__setattr__:这些方法允许你动态地获取和设置对象的属性。当你访问一个不存在的属性时,__getattr__方法会被调用。当你设置一个属性时,__setattr__方法会被调用。 __call__:这个方法允许你将对象作为函数调用。当你调用一个对象时,Python实际上是在调用对象的__call__方法。 除了上面列举的方法,还有许多其他的魔术方法,例如__cmp__,__hash__,__iter__等等。学习这些魔术方法将使你能够更好地理解Python的面向对象编程模型。 总之,学习和理解魔术方法是Python面向对象编程中的一个关键概念,因为它们可以帮助你实现更加灵活和强大的代码。如果你想成为一名Python高手,那么深入学习魔术方法是不可避免的。 ### 回答3: Python中的“魔术方法”指的是每个中定义的特殊方法,它们以双下划线(__)开头和结尾,并且有着特定的用途。通过使用这些魔法方法,我们可以自定义的行为,并为程序提供更高级别的功能。 以下是Python中常用的一些魔术方法: 1. __init__:这是最常用的魔术方法之一,它用于初始化一个对象,以及定义的属性和方法。 2. __str__:此方法用于返回对象的字符串表示形式,似于Java中的toString()方法。 3. __repr__:与__str__似,但是返回的是对象的“官方”字符串表示形式,通常用于调试和开发。 4. __getattr__:当试图访问一个不存在的属性时,此方法被调用。 5. __setattr__:当尝试设置的属性时,此方法被调用。 6. __delattr__:当尝试删除的属性时,此方法被调用。 7. __call__:将对象作为函数调用时,此方法被调用。 8. __len__:返回对象的长度。 9. __getitem__:允许通过索引访问对象的元素。 10. __setitem__:允许通过索引设置对象的元素。 11. __delitem__:允许通过索引删除对象的元素。 通过了解和使用这些魔术方法,我们可以编写出更高效、更灵活、更具可读性的Python代码,并且实现似于内置型一样的功能。例如,我们可以实现一个自定义列表,似于Python的list型,然后使用上述魔术方法来访问、设置和删除元素。同时,我们还可以自定义变量和函数的行为,使我们的Python代码变得更具有表现力和弹性。 总之,了解和掌握Python的魔术方法是Python编程中必不可少的一部分,对于理解和编写实际应用程序非常有价值。在实践中,我们可以根据实际情况选择恰当的魔术方法,从而创建更灵活、更高效的Python

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值