vps装网站管理系统,万家灯火网站建设,爱是做的电影网站,自学网站建设要多久关注这个专栏的其他相关笔记#xff1a;[Web 安全] 反序列化漏洞 - 学习笔记-CSDN博客 PHP 魔术方法 - 简介 - PHP 魔术方法 - 简单教程#xff0c;简单编程PHP 中#xff0c;以两个下划线 ( __ ) 开头方法称之为 「 魔术方法 」 这些 「 魔术方法 」 在 [PHP](/l/yufei/php… 关注这个专栏的其他相关笔记[Web 安全] 反序列化漏洞 - 学习笔记-CSDN博客 PHP 魔术方法 - 简介 - PHP 魔术方法 - 简单教程简单编程PHP 中以两个下划线 ( __ ) 开头方法称之为 「 魔术方法 」 这些 「 魔术方法 」 在 [PHP](/l/yufei/php/php-basic-index.html) 中扮演这重要的角色作为一名 PHP 开发人员你必须知道它们且会用它们 本专栏我们就来看看和学习这些魔术方法以及一些简单的使用范例 ## PHP 魔术方法一览 |方法名|说明| |:---|:---| |\__construct()类的构造函数 |\__destruct()| 类 - 简单教程简单编程 https://twle.cn/c/yufei/phpmmethod/phpmmethod-basic-index.html
0x01PHP 魔术方法简介
在 PHP 中以两个下划线__开头的方法就被称为「 魔术方法 」。魔术方法是 PHP 中一个预定好的在特定情况下会自动触发的行为方法。 这些魔术方法在 PHP 中扮演着重要的角色作为一名 PHP 开发人员我们必须要掌握并且能熟练使用它们。下面开始本章的学习以下是常见的 PHP 魔术方法及其作用简介
方法名作用解析__construct()类的构造函数创建对象时触发__destruct()类的析构函数对象被销毁时触发__call()当调用对象的一个不存在或不可访问的方法时会自动调用__callStatic()当调用对象或类的一个不存在或不可访问的静态方法时会自动调用__get()调用不可访问、不存在的对象成员属性时触发__set()在给不可访问、不存在的对象成员属性赋值时触发__isset()当对不可访问属性调用 isset() 或 empty() 时触发__unset()当使用 reset() 重制一个对象不存在的或不可访问的属性时会自动调用__invoke()把对象当作函数调用时触发__sleep()执行 serialize() 函数前会先调用此方法。__wakeup()执行 unserialize() 函数前会先调用此方法。__toString()当把对象当成字符串调用时会触发此方法__clone()使用 clone 关键字拷贝完一个对象后触发__set_state()当使用 var_export() 将数组导出为变量时会自动调用__autoload()尝试自动加载一个未定义的类__debugInfo()打印输出调试信息针对 var_dump() 函数
0x02PHP 魔术方法 — __construct()
0x0201方法简介
PHP 构造函数 __construct() 是对象被创建后自动调用的第一个方法。
任何类都会有一个构造函数当我们没有显示的声明它时系统其实已经为它创建了一个隐藏的默认的构造函数这个默认的构造函数没有任何参数也不会执行任何代码等价于一个空函数。
一旦我们在类中显式的声明了一个构造函数那么默认的构造函数就会消失也可以说是我们创建的构造函数会覆盖掉系统默认的构造函数。
0x0202方法作用
构造函数通常用于执行一些初始化任务例如在创建对象时设置成员变量的初始值。
0x0203方法声明
在类中声明一个构造函数的语法格式一般如下 class ClassName {function __construct([parameter list]){// 函数主体这里面通常用于初始化对象的一些属性}} 注意一个 PHP 类中只能有一个构造函数因为 PHP 不允许进行函数重载 0x0204调用示例
下面的代码声明了一个 Dog 类同时在该类中创建了一个构造函数用于初始化对象的相应属性 ?phpclass Dog {public $name; // 姓名public $age; // 年龄function __construct($name, $age) {echo 恭喜你你成功创建了一只 \n;$this - name $name; // 初始化 Dog 的名称echo Dog Name : . $this - name . \n;$this - age $age; // 初始化 Dog 的年龄echo Dog Age : . $this - age . \n;}}$dog new Dog(旺财, 10); // 实例化一只小狗 如上可以看到我们只是实例化了 Dog 类并没有主动调用类中的方法__construct() 方法就自己调用了。
0x03PHP 魔术方法 — __destruct()
0x0301方法简介
__destruct() 方法会在该类的一个对象被删除时自动调用。一般情况下该函数的触发时机为 主动调用 unset($obj)。 主动调用 $obj NULL。 程序自动结束。
0x0302方法作用
__destruct() 函数通常被用于对象执行完毕后进行释放资源的操作比如关闭文件、关闭数据库链接、清空一个结果集等。
0x0303方法声明
在类中声明 __destruct() 函数的语法格式如下该函数没有任何参数也没有任何返回值 class ClassName {function __destruct() {// 其他代码}}
0x0304调用示例
在下面这个例子中我们给 Dog 类添加上析构函数 __destruct()当对象走向消亡生命周期结束时它会进行提示 ?phpclass Dog {public $name; // 姓名public $age; // 年龄function __construct($name, $age) {echo 恭喜你你成功创建了一只 \n;$this - name $name; // 初始化 Dog 的名称echo Dog Name : . $this - name . \n;$this - age $age; // 初始化 Dog 的年龄echo Dog Age : . $this - age . \n;}function __destruct() {echo destruct \n;echo 快乐的时光总是短暂的你的 . $this - name . 还是走向了它的终点\n;echo 请不要伤心它的故事只是已另一种形式展开。。。。。;}}$dog new Dog(旺财, 10); // 实例化一只小狗 0x04PHP 魔术方法 — __call()
0x0401方法简介
__call() 方法只能被用于类中当程序尝试调用类对象的一个 不存在 的或者 不可访问 的方法或属性时会被自动调用。
0x0402方法声明
该方法有两个参数第一个参数是调用的那个不存在的 方法名第二个参数是一个数组array是传递给不存在方法的所有参数组成的数组 class ClassName {function __call( string $func_name, array $args) {// 内部代码}}
0x0403调用示例
如下我们给 Dog 类创建了一个 __call 方法用于在程序调用其中不存在的方法时进行自动调用 ?phpclass Dog {public $name; // 姓名public $age; // 年龄function __construct($name, $age) {echo 恭喜你你成功创建了一只 \n;$this - name $name; // 初始化 Dog 的名称echo Dog Name : . $this - name . \n;$this - age $age; // 初始化 Dog 的年龄echo Dog Age : . $this - age . \n;}function __call($func_name, $args) {echo Call Error ! \n;echo Sorry, . $this - name . 不会 .$func_name . \n;print_r($args);}}$dog new Dog(旺财, 1); // 实例化一只小狗$dog - fly(高高, $hight100 米); // 让小狗飞高高想飞 100 米那么高 0x05PHP 魔术方法 — __callStatic()
0x0501方法简介
__callStatic() 会在程序调用一个不存在的静态方法该方法不存在或者不可访问时被自动调用。
0x0502方法声明
该方法接收两个参数第一个参数是调用的那个不存在的静态方法名第二个参数是一个数组array是传递给不存在的静态方法的所有参数组成的数组 class ClassName {static function __callStatic( string $func_name, array $args) {// 内部代码}}
0x0503调用示例
如下我们给 Dog 类创建了一个 __callStatic 方法用于在程序调用其中不存在的静态类时自动触发 ?phpclass Dog {public $name; // 姓名public $age; // 年龄function __construct($name, $age) {echo 恭喜你你成功创建了一只 \n;$this - name $name; // 初始化 Dog 的名称echo Dog Name : . $this - name . \n;$this - age $age; // 初始化 Dog 的年龄echo Dog Age : . $this - age . \n;}static function __callStatic($name, $arguments) {echo Call Error ! \n;echo 静态方法 . $name . 不存在\n;print_r($arguments);}}$dog new Dog(旺财, 1); // 实例化一只小狗// 下面就是调用静态方法的写法$dog::fly(高高, $hight100 米); // 让小狗飞高高想飞 100 米那么高 0x06PHP 魔术方法 — __get()
0x0601方法简介
当一个类定义了一个 __get() 魔术方法后我们就可以获取该类的实例的私有属性或不存在的属性而不犯错这里所说的获取是指获取其值。
0x0602方法声明
该方法的原型如下
class ClassName {public mixed function __get( string $propertyName ) {// 内部代码}
}
0x0603调用示例
在下面的示例中我们创建了一个 Dog 类并为其添加了 __get() 魔法方法当程序调用类中不存在的属性时就会提示报错
?phpclass Dog {public $name; // 姓名public $age; // 年龄function __construct($name, $age) {echo 恭喜你你成功创建了一只 \n;$this - name $name; // 初始化 Dog 的名称echo Dog Name : . $this - name . \n;$this - age $age; // 初始化 Dog 的年龄echo Dog Age : . $this - age . \n;}public function __get($propertyName) {echo Get Error ! \n;echo Sorry, The Dog Class Didnt have . $propertyName . attribute\n;}
}$dog new Dog(旺财, 1); // 实例化一只小狗
echo $dog - type; // 想要知道 Dog 属于哪类 0x07PHP 魔术方法 — __set()
0x0701方法简介
魔术方法 __set() 可以用来给类的实例的不存在的属性或不可访问的属性赋值。
0x0702方法声明
该方法有两个参数第一个参数 $property 是不存在的或不可访问的实例属性第二个参数 $value 是实际要赋的值。
该方法可以有返回值也可以没有返回值这取决于开发者的要求
class ClassName {public function __set( $propertyName, $value ) {// 内部代码}
}
0x0703调用示例
在如下示例中当我们为私有属性 age 赋值时就会触发类中的 __set 方法做一个简单的判断不让这个年龄过大或者过小
?phpclass Dog {public $name; // 姓名private $age; // 年龄function __construct($name, $age) {echo 恭喜你你成功创建了一只 \n;$this - name $name; // 初始化 Dog 的名称echo Dog Name : . $this - name . \n;$this - age $age; // 初始化 Dog 的年龄echo Dog Age : . $this - age . \n;}public function __set($propertyName, $value) {print_r( Set \n);if ($propertyName age) {if ($value 0 or $value 35) {echo Error! Your Dog Age IS Error !!!\n; // 当设置的年龄超过了狗年龄的范围时触发} else {$this - age $value;echo Now, Your Dog Age is . $this - age . \n;}}}
}$dog new Dog(旺财, 1); // 实例化一只小狗
$dog - age 100; // 想让狗的年龄变成 100 岁
$dog - age 18; // 想让狗的年龄回到 18 岁 0x08PHP 魔术方法 — __isset()
0x0801方法简介
在讨论 __isset() 魔术方法之前笔者先简单介绍一下 isset() 方法该方法主要用于判断一个变量或一个实例的一个属性是否被定义。
如果变量或实例的属性不存在或被赋值为 NULL就会返回 false其它情况下一律返回 true哪怕目标被赋值为 false0。
isset() 通常用于判断某个变量是否被设置但它同时可以在外部实例中判断实例的某个属性值是否被设置这通常有两个常见 如果属性是公开public属性那么可以直接使用 isset()来判断该属性是否设置。 如果属性是一个私有private的属性那么 isset() 就无法正常工作了。
针对上述的第二种情况我们就需要用到 __isset() 方法了。
0x0802方法作用
通过在类中定义 __isset() 魔术方法我们就可以使用 isset() 来判断这个类的实例的某个私有属性是否被 “设置”只要 __isset() 返回 true那么 isset() 方法就会返回 true反之亦然。
0x0803方法声明
该方法只接收一个参数就是要进行判断的属性名该方法的返回值为一个 Bool 类型
class ClassName {public bool function __isset( $propertyName ) {// 内部代码return [true or false];}
}
0x0804调用示例
在下面的代码中类中的 age 属性为私有的要想判断实例的 age 属性是否被设置我们就要借助 __isset() 方法
?phpclass Dog {public $name; // 姓名private $age; // 年龄function __construct($name, $age) {echo 恭喜你你成功创建了一只 \n;$this - name $name; // 初始化 Dog 的名称echo Dog Name : . $this - name . \n;$this - age $age; // 初始化 Dog 的年龄echo Dog Age : . $this - age . \n;}public function __isset($property) {print_r(WUHU, {$property} is a private attribute, __isset function is auto runs!!!\n);return isset($this - $property);}
}$dog new Dog(旺财, 1); // 实例化一只小狗
var_dump(isset($dog - age)); 0x09PHP 魔术方法 — __unset()
0x0901方法简介
如果一个类中定义了魔术方法 __unset()那么我们就可以使用 unset() 函数来销毁类的私有属性或在销毁一个不存在的属性时得到通知。
然而实际上到底有没有销毁那个属性取决于 __unset() 的具体实现假如我们定义了一个空的 __unset() 方法emmmm没人这么闲吧。
0x0902方法声明
该方法的原型如下
class ClassName {public function __unset( $propertyName ) {// 内部代码}
}
0x0903调用示例
在下面的示例中我们在 Dog 类中定义了一个 __unset() 方法并用它尝试销毁类中的一个私有属性与一个不存在的属性
?phpclass Dog {public $name; // 姓名private $age; // 年龄function __construct($name, $age) {echo 恭喜你你成功创建了一只 \n;$this - name $name; // 初始化 Dog 的名称echo Dog Name : . $this - name . \n;$this - age $age; // 初始化 Dog 的年龄echo Dog Age : . $this - age . \n;}public function __unset( $property ) {if ($property ! age) {echo 啊哦, 你销毁的东东不存在 !!!!\n;} else {echo $property 已成功被销毁 !!!\n;unset($this - $property);}}
}$dog new Dog(旺财, 1); // 实例化一只小狗
unset($dog - type); // 尝试销毁不存在的 Type 属性
unset($dog - age); // 尝试销毁类的私有属性 age 0x10PHP 魔术方法 — __sleep()
0x1001方法简介
当我们在 PHP 中调用 serialize() 函数尝试序列化一个实例时会首先检查该实例中是否存在 __sleep() 方法如果该方法存在则自动调用否则使用默认的序列化方式。
0x1003方法声明
我们可以在 __sleep() 方法中定制类的实例的序列化输出结果并剔除一些不需要被序列化的属性比如那些保存了超大数据的属性。
该魔术方法没有任何参数单必须要有返回值返回值的类型是 Array 类的它包含了想要序列化的该实例的属性名
class ClassName {public array function __sleep() {// 内部代码return array();}
}
0x1004调用示例
比如下面这个例子我们创建了一个 Dog 类当程序序列化该类对象时我们剔除了 $age 属性并对 $name 属性进行了编码操作
?phpclass Dog {public $name; // 姓名private $age; // 年龄function __construct($name, $age) {echo 恭喜你你成功创建了一只 \n;$this - name $name; // 初始化 Dog 的名称echo Dog Name : . $this - name . \n;$this - age $age; // 初始化 Dog 的年龄echo Dog Age : . $this - age . \n;}function __sleep() {print_r( Dog 类正在序列化 Ing );$this - name base64_encode($this - name);$this - type Dog; // 临时创建一个属性return array(name, type); // 返回的时候排除了 $age 属性}
}$dog new Dog(旺财, 1); // 实例化一只小狗
echo serialize($dog); // 对 dog 进行序列化 0x11PHP 魔术方法 — __wakeup()
0x1101方法简介
当我们在 PHP 中使用 unserialize() 反序列化一个对象时如果类中存在 __wakeup() 方法那么该方法就会被自动调用。
0x1102方法声明
该魔术方法既没有参数也没有返回值
class ClassName {public function __wakeup() {// 内部代码}
}
0x1103调用示例
下面示例中我们往 Dog 类中添加了反序列化方法用来在反序列化时对 $name 进行 Base64 解码
?phpclass Dog {public $name; // 姓名private $age; // 年龄function __construct($name, $age) {echo 恭喜你你成功创建了一只 \n;$this - name $name; // 初始化 Dog 的名称echo Dog Name : . $this - name . \n;$this - age $age; // 初始化 Dog 的年龄echo Dog Age : . $this - age . \n;}function __sleep() {print_r( Dog 类正在序列化 Ing );$this - name base64_encode($this - name);$this - type Dog; // 临时创建一个属性return array(name, type); // 返回的时候排除了 $age 属性}function __wakeup() {print_r( Dog 类正在反序列化 Ing );$this - name base64_decode($this - name); // 对 Dog 名称进行 Base64 解码}
}$dog new Dog(旺财, 1); // 实例化一只小狗$serialize_dog serialize($dog); // 对 dog 进行序列化
echo $serialize_dog . \n;$new_dog unserialize($serialize_dog);
echo \nDog 的名称: . $new_dog - name; 0x12PHP 魔术方法 — __toString()
0x1201方法简介
当我们使用 echo 语句尝试输出一个对象时就会自动检查一个对象有没有定义 __toString() 方法如果定义了就会输出 __toString() 方法的返回值如果没有定义那么就会直接抛出一个异常表明该对象不能直接转换为字符串。
0x1202方法声明
该方法没有任何参数也不会传递任何参数但该方法必须有一个返回值且返回值必须为字符串类型
class ClassName {public string function __toString() {// 内部代码}
}
0x1203调用示例
在下面例子中我们为 Dog 类新增添了一个 __toString() 方法并通过 echo 输出了该类
?phpclass Dog {public $name; // 姓名private $age; // 年龄function __construct($name, $age) {echo 恭喜你你成功创建了一只 \n;$this - name $name; // 初始化 Dog 的名称echo Dog Name : . $this - name . \n;$this - age $age; // 初始化 Dog 的年龄echo Dog Age : . $this - age . \n;}public function __toString() {return sprintf(Dog(%s, %s), $this - name, $this - age);}
}$dog new Dog(旺财, 1); // 实例化一只小狗
echo $dog; 0x13PHP 魔术方法 — __invoke()
0x1301方法简介
当我们尝试将一个对象当作一个方法来使用时就会自动调用它的 __invoke() 方法如果目标对象中不包含该方法就会直接报错。
0x1302方法声明
该方法可以有返回值也可以没有对于返回值的类型它也没有任何限制
class ClassName {public mixed function __invoke() {// 内部代码}
}
0x1303调用示例
下面的代码我们给 Dog 类加上了 __invoke() 魔术方法然后我们就可以将它的实例当作普通方法来调用了
?phpclass Dog {public $name; // 姓名private $age; // 年龄function __construct($name, $age) {echo 恭喜你你成功创建了一只 \n;$this - name $name; // 初始化 Dog 的名称echo Dog Name : . $this - name . \n;$this - age $age; // 初始化 Dog 的年龄echo Dog Age : . $this - age . \n;}function __invoke() {echo Hello, My Name is . $this - name . I am .$this -age . Years Old Now !!!;}
}$dog new Dog(旺财, 1); // 实例化一只小狗
$dog(); // 把 dog 对象当作方法调用