魔术方法
魔术方法
总结
- __construct(),类的构造函数
- __destruct(),类的析构函数
- __call(),在对象中调用一个不可访问方法时调用
- __callStatic(),用静态方式中调用一个不可访问方法时调用
- __get(),获得一个类的成员变量时调用
- __set(),设置一个类的成员变量时调用
- __isset(),当对不可访问属性调用isset()或empty()时调用
- __unset(),当对不可访问属性调用unset()时被调用。
- __sleep(),执行serialize()时,先会调用这个函数
- __wakeup(),执行unserialize()时,先会调用这个函数
- __toString(),类被当成字符串时的回应方法
- __invoke(),用调用函数的方式去调用一个对象时的回应方法
- __set_state(),调用var_export()导出类时,此静态方法会被调用。
- __clone(),当对象复制完成时调用
- __autoload(),尝试加载未定义的类
- __debugInfo(),打印所需调试信息
1.__construct()
作用:用来执行一些有用的初始化任务,如对成员属性在创建对象时赋予初始值
格式
function __construct([参数列表]){
方法体//通常用来对成员属性进行初始化赋值
}
创建对象 不带参数
$Person1 = new Person();
echo $Person1->say(); //输出:我叫:,性别:男,年龄:22
创建对象带一个参数
$Person2 = new Person("李华");
echo $Person2->say(); //输出:我叫:李华,性别:男,年龄:22
创建对象带三个参数
<?php
class Person{
public $name;
public $sex;
public $age;
//声明一个构造方法且带参数
public function __construct($name="",$sex="男",$age="16"){
$this->name = $name;
$this->sex = $sex;
$this->age = $age;
}
//say方法
public function say(){
echo "我叫:". $this->name . ",性别:" . $this->sex . ",年龄:" . $this->age;
}
}
$Person1 = new Person("李华");
echo $Person1->say();
输出结果
我叫:李四,性别:男,年龄:25
2.__destruct()
作用:用来完成一些在对象销毁前的清理任务
格式
function __destruct(){
//方法体
}
注:不能带有任何参数
<?php
class Person{
public $name;
public $sex;
public $age;
public function __construct($name="",$sex="女",$age=17)
{
$this->name = $name;
$this->sex = $sex;
$this->age = $age;
}
public function say(){
echo "我叫:" . $this->name . ",性别:" . $this->sex . ",年龄:" . $this->age;
}
//声明一个构造方法
public function __destruct(){
echo "我觉得我还可以再抢救一下,我的名字叫".$this->name;
}
}
$Person = new Person("小美");
unset($Person);//销毁上面创建的对象$Person
输出结果
我觉得我还可以再抢救一下,我的名字叫小明
3.__call()
在对象中调用一个不可访问方法时调用
作用:为了避免当调用的方法不存在时产生错误,而意外的导致程序中止,可以使用 __call() 方法来避免。
该方法在调用的方法不存在时会自动调用,程序仍会继续执行下去。
用法:该方法有两个参数,第一个参数 $function_name
会自动接收不存在的方法名,第二个 $arguments
则以数组的方式接收不存在方法的多个参数
格式
function __call(string $function_name, array $arguments)
{
// 方法体
}
<?php
class Person{
function say(){
echo "Hello world!";
}
//声明此方法用来处理调用对象中不存在的方法
function __call($funName,$arguments){
echo "你所调用的函数:".$funName . "(参数:";//输出调用不存在的方法名
print_r($arguments);// 输出调用不存在的方法时的参数列表
echo ")不存在!\n";// 结束换行
}
}
$Person =new Person();
$Person->run("teacher");// 调用对象中不存在的方法,则自动调用了对象中的__call()方法
$Person->eat("小美","草莓");
$Person->say();
输出结果
你所调用的函数:run(参数:Array ( [0] => teacher ) )不存在!
你所调用的函数:eat(参数:Array ( [0] => 小明 [1] => 苹果 ) )不存在!
Hello, world!
4.__callStatic()
用静态方式中调用一个不可访问方法时调用
此方法与上面所说的 call() 功能除了 callStatic() 是未静态方法准备的之外,其它都是一样的。
<?php
class Person{
function say(){
echo "Hello world!";
}
public static function __callStatic($funName, $arguments)
{
echo "你所调用的静态方法:".$funName."(参数:";
print_r($arguments);
echo ")不存在!\n";
}
}
$Person=new Person();
$Person::run("teacher");
$Person::eat("小明", "苹果");
$Person->say();
输出结果
你所调用的静态方法:run(参数:Array ( [0] => teacher ) )不存在!
你所调用的静态方法:eat(参数:Array ( [0] => 小明 [1] => 苹果 ) )不存在!
Hello, world!
5.__get()
获得一个类的成员变量时调用,解决private“不能访问某个私有属性”时调用
<?php
class Person{
private $name;
private $age;
function __construct($name="",$age=1){
$this->name=$name;
$this->age=$age;
}
public function __get($propertyName){
if ($propertyName == "age"){
if ($this->age >30){
return $this->age -10;
}else{
return $this->$propertyName;
}
}else{
return $this->$propertyName;
}
}
}
$Person=new Person("小美",61);
echo "姓名:".$Person->name;
echo "年龄:".$Person->age;
输出结果
姓名:小美年龄:51
6.__set()
__set( $property, $value )` 方法用来设置私有属性, 给一个未定义的属性赋值时,此方法会被触发,传递的参数是被设置的属性名和值
<?php
class Person
{
private $name;
private $age;
public function __construct($name = "", $age = 25)
{
$this->name = $name;
$this->age = $age;
}
public function __set($property, $value)
{
if ($property == "age") {
if ($value > 150 || $value < 0) {
return;
}
}
$this->$property = $value;
}
public function say()
{
echo "我叫" . $this->name . ",今年" . $this->age . "岁了";
}
}
$Person=new Person("小美",17);
$Person->name="小红";
$Person->age=15;
$Person->age=163;
$Person->say();
输出结果
我叫小红,今年15岁了
7.__isset()
当对不可访问的属性调用isset()或empty()时调用
isset)_函数是测定变量是否设定的函数,传入一个变量作为参数,如果传入的变脸存在就返回true,否则返回false
在一个对象外面使用isset()函数去测定对象里面的陈鸿源是否被设定分两种情况:
(1)对象里面成员是公有的->(√)
(2)私有属性成员->(X) 若是在类里面加上__isset()函数就可以了
即:当在类的外部使用isset()函数来测定对象里面的私有成员是否被设定时,就会自动调用类里面的__isset()函数
<?php
class Person{
public $sex;
private $name;
private $age;
public function __construct($name="",$age=18,$sex='男')
{
$this->name = $name;
$this->age = $age;
$this->sex = $sex;
}
public function __isset($content){
echo "当在类外部使用isset()函数测定私有成员{$content}时,自动调用";
echo isset($this->$content);
}
}
$Person =new Person("小美",18);
echo isset($Person->sex);
echo isset($Person->name);
echo isset($Perosn->age);
输出结果
1当在类外部使用isset()函数测定私有成员name时,自动调用1
8.__unset()
unset()函数是删除指定的变量且回传true,参数为要删除的变量
(1)如果一个对象里面的成员属性是公有的,可以使用这个函数在对象外面删除对象的公有属性
(2) 如果对象的成员属性是私有的,这个函数就没有权限去删除
即 在对象里面加上unset函数 就可以在对象外面删除对象里面的私有成员属性,对象会自动调用unset()函数来删除对象内部的私有成员属性
<?php
class Person{
public $sex;
private $name;
private $age;
public function __construct($name="",$age=18,$sex='男')
{
$this->name = $name;
$this->$age = $age;
$this->sex = $sex;
}
public function __unset($content)
{
echo "当在类的外部使用unset()函数来删除私有成员时自动调用";
echo isset($this->content);
}
}
$Person =new Person("小美",18);
unset($Person->sex);
unset($Person->name);
unset($Person->age);
输出结果
当在类的外部使用unset()函数来删除私有成员时自动调用当在类的外部使用unset()函数来删除私有成员时自动调用
9.__sleep()
serialize()
函数会检查类中是否存在一个魔术方法 __sleep()
。如果存在,则该方法会优先被调用,然后才执行序列化操作
此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组
如果该方法未返回任何内容,则 NULL 被序列化,并产生一个 E_NOTICE 级别的错误
__sleep()不能返回父类的私有成员的名字。这样做会产生一个 E_NOTICE 级别的错误。可以用 Serializable 接口来替代.
__sleep() 方法常用于提交未提交的数据,或类似的清理操作。同时,如果有一些很大的对象,但不需要全部保存,这个功能就很好用。
<?php
class Person{
public $sex;
public $name;
public $age;
public function __construct($name="",$age="",$sex='男'){
$this->name = $name;
$this->age = $age;
$this->sex = $sex;
}
public function __sleep()
{
echo "当在类的外部使用serialize()时会调用这里的__sleep()方法";
$this->name = base64_encode($this->name);
return array('name','age');
}
}
$Person = new Person('小美');
echo serialize($Person);
输出结果
当在类的外部使用serialize()时会调用这里的__sleep()方法O:6:"Person":2:{s:4:"name";s:8:"5bCP576O";s:3:"age";s:0:"";}
10.__wakeup()
unserialize()会检查是覅否存在一个wakeup()方法,如果存在则会优先调用wakeup方法,预先准备对象需要的资源。
<?php
class Person{
public $sex;
public $name;
public $age;
public function __construct($name="",$age=18,$sex='男'){
$this->name = $name;
$this->age = $age;
$this->sex = $sex;
}
public function __sleep()
{
echo "当在类的外部使用serialize()时,会调用这里的__sleep()方法";
$this->name = base64_encode($this->name);
return array('name','age');
}
public function __wakeup(){
echo "当前类外部使用unserialize()时会调用这里的__wakeup()方法";
$this->name=2;
$this->sex='男';
}
}
$Person = new Person('小美');
var_dump(serialize($Person));
var_dump(unserialize(serialize($Person)));
输出结果
当在类的外部使用serialize()时,会调用这里的__sleep()方法string(58) "O:6:"Person":2:{s:4:"name";s:8:"5bCP576O";s:3:"age";i:18;}"
当在类的外部使用serialize()时,会调用这里的__sleep()方法当前类外部使用unserialize()时会调用这里的__wakeup()方法object(Person)#2 (3) {
["sex"]=>
string(3) "男"
["name"]=>
int(2)
["age"]=>
int(18)
}
11.__toString()
一个类被当成字符串时的回应方法(次啊方法必须返回一个字符串否则报错)
<?php
class Person
{
public $sex;
public $name;
public $age;
public function __construct($name = "", $age = 18, $sex = '男')
{
$this->name = $name;
$this->age = $age;
$this->sex = $sex;
}
public function __toString()
{
return 'go go go';
}
}
$Person = new Person('小美');
echo $Person;
输出结果
go go go
12.__invoke()
当尝试调用函数的方式调用一个对象时,__invoke()方法会被自动调用
<?php
class Person
{
public $sex;
public $name;
public $age;
public function __construct($name = "", $age = 18, $sex = '男')
{
$this->name = $name;
$this->age = $age;
$this->sex = $sex;
}
public function __invoke(){
echo '这是一个对象';
}
}
$Person = new Person('小美');
$Person();
输出:这是一个对象
若还执意调用 则会报错
13.__set_state()
作用:当调用var_export()导出类时,此方法被调用
参数:本方法的唯一参数时数组,其中包含array(’property‘ = >value,..)格式排列的类
<?php
class Person
{
public $sex;
public $name;
public $age;
public function __construct($name = "", $age = 18, $sex = '男')
{
$this->name = $name;
$this->age = $age;
$this->sex = $sex;
}
public function __set_state($an_array){
$a=new Person();
$a->name=$an_array['name'];
return $a;
}
}
$Person = new Person('小美');
$Person->name ='小米';
var_dump($Person);
输出结果
object(Person)#1 (3) {
["sex"]=>
string(3) "男"
["name"]=>
string(6) "小米"
["age"]=>
int(18)
}
14.__clone()
当对象复制完成时调用
对象复制可以通过 clone 关键字来完成(如果可能,这将调用对象的 clone() 方法)。对象中的 clone() 方法不能被直接调用。
语法:
$copy_of_object = clone $object;
当复制完成时,如果定义了 clone() 方法,则新创建的对象(复制生成的对象)中的 clone() 方法会被调用,可用于修改属性的值
<?php
class Person
{
public $sex;
public $name;
public $age;
public function __construct($name = "", $age = 18, $sex = '男')
{
$this->name = $name;
$this->age = $age;
$this->sex = $sex;
}
public function __clone(){
echo __METHOD__."你正在克隆对象";
}
}
$Person = new Person('小美');
$Person2 = clone $Person;
var_dump('Persion1:');
var_dump($Person);
输出结果
Person::__clone你正在克隆对象string(9) "Persion1:"
object(Person)#1 (3) {
["sex"]=>
string(3) "男"
["name"]=>
string(6) "小美"
["age"]=>
int(18)
} //克隆成功
15.__sutoload()
尝试加载未定义的类
<?php
class Person
{
public $sex;
public $name;
public $age;
public function __construct($name = "", $age = 18, $sex = '男')
{
$this->name = $name;
$this->age = $age;
$this->sex = $sex;
}
public function __autolaod( $className){
$filePAth = "project/calss/{$className}.php";
if (is_readable($filePAth)){
require($filePAth);
}
}
}
if (条件A){
$a = new A();
$b = new B();
$c = new C();
}else if (条件B){
$a =newA();
$b = new B();
}
第一次使用 类A,但是找不到时,会自动调用autoload方法,并将类名A作为参数传入,所以需要在autoload()中根据类名找到相应的文件,并包含进来。如果方法也找不到就会报错
16.__debugInfo
打印所需调试的信息
<?php
class C{
private $prop;
public function __construct($val){
$this->prop = $val;
}
public function __debugInfo()
{
return [
'propSquared' =>$this->prop **2,
];
}
}
var_dump(new C(42));
输出结果
object(C)#1 (1) {
["propSquared"]=>
int(1764)
}