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);