带你吃透16个PHP魔术方法

什么是魔术方法?本篇文章带大家了解一下16个PHP 开发者必知必会的魔术方法,希望对大家有所帮助! 在PHP中,以双下划线(__)开始命名的方法被称作PHP中的魔术方法,它们在PH…

什么是魔术方法?本篇文章带大家了解一下16个PHP 开发者必知必会的魔术方法,希望对大家有所帮助!

带你吃透16个PHP魔术方法

在PHP中,以双下划线(__)开始命名的方法被称作PHP中的魔术方法,它们在PHP中充当很重要的角色。魔术方法包括:

方法名描述__construct()类的构造函数__destruct()类的析构函数__call($funName, $arguments)当调用一个未定义或不可达方法时, __call() 方法将被调用。__callStatic($funName, $arguments)当调用一个未定义或不可达的静态方法时, __callStatic() 方法将被调用。__get($propertyName)当获取一个类的成员变量时, __get() 方法将被调用。__set($property, $value)当赋值一个类的成员变量时, __set() 方法将被调用。__isset($content)当调用 isset() 或 empty() 对一个未定义或不可达的成员赋值时, __isset() 方法将被调用。__unset($content)当调用 reset() 对一个未定义或不可达的成员更新时, __unset() 方法将被调用。__sleep()当执行序列化 serialize() 时,__sleep() 方法将首先被调用。__wakeup()当执行反序列化 deserialization() 时, __wakeup() 方法将首先被调用。__toString()当使用 echo 方法直接输出显示对象时,__toString() 方法首先被调用。__invoke()使用调用函数(function)访问一个对象时, __invoke() 方法将首先被调用。__set_state($an_array)当调用 var_export() 方法时,__set_state() 方法将被调用。__clone()当对象被复制赋值时,__clone() 方法将被调用。__autoload($className)试图载入一个未定义的类时调用。__debugInfo()输出 debug 信息。

本文将使用一些实例展示 PHP 魔术方法的运用。

1.__construct()

当创建对象时,PHP 类的构造方法是第一个被调用的方法。每个类都有构造方法。若你没在类中明确声明定义它,将会有一个默认的无参类构造方法存在,虽然它不会在类中定义出现。

1) 构造方法的运用

类的构造方法通常用于执行一些初始化任务,诸如当创建对象时,为成员初始化赋值。

2) 类中构造方法的声明格式

function__constrct([parameterlist]){方法具体实现//通常为成员变量初始赋值。}

注意: 在多数类中仅可以声明一个构造方法。因为, PHP 不支持构造方法重载。

下面是个完整的例子:

<?phpclassPerson{public$name;public$age;public$sex;/***明确定义含参的构造方法*/publicfunction__construct($name="",$sex="Male",$age=22){$this->name=$name;$this->sex=$sex;$this->age=$age;}/***say方法定义*/publicfunctionsay(){echo"Name:".$this->name.",Sex:".$this->sex.",Age:".$this->age;}}

无参创建 $Person1 对象。

$Person1=newPerson();echo$Person1->say();//显示:Name:,Sex:Male,Age:22

使用一个参数 "Jams" 调用创建 $Person2 对象。

$Person2=newPerson("Jams");echo$Person2->say();//显示:Name:Jams,Sex:Male,Age:22

使用3个参数调用创建 $Person3 对象。

$Person3=newPerson("Jack","Male",25);echo$Person3->say();//显示:Name:Jack,Sex:Male,Age:25

2. __destruct()

析构函数与构造函数相反。

析构函数允许你在销毁对象之前执行一些操作,例如关闭文件,清空结果集等等。

析构函数是 PHP 5 引入的新功能。

析构函数的声明与构造函数类似,以两个下划线开头,名称固定为__destruct()。

析构函数的声明

function__destruct(){//methodbody}

析构函数不能带参数。

析构函数的使用

析构函数在类中一般不常见。它是类的可选部分,通常用于在类销毁之前完成一些清理任务。

这是使用析构函数的示例:

<?phpclassPerson{public$name;public$age;public$sex;publicfunction__construct($name="",$sex="Male",$age=22){$this->name=$name;$this->sex=$sex;$this->age=$age;}/***saymethod*/publicfunctionsay(){echo"Name:".$this->name.",Sex:".$this->sex.",Age:".$this->age;}/***declareadestructormethod*/publicfunction__destruct(){echo"Well,mynameis".$this->name;}}$Person=newPerson("John");unset($Person);//destroytheobjectof$Personcreatedabove

输出结果

Well,mynameisJohn

3. __call()

该方法接受两个参数。第一个参数为未定义的方法名称,第二个参数则为传入方法的参数构成的数组

使用

function__call(string$function_name,array$arguments){//methodbody}

在程序中调用未定义方法时,__call()方法将被调用。

示例

<?phpclassPerson{functionsay(){echo"Hello,world!<br>";}function__call($funName,$arguments){echo"Thefunctionyoucalled:".$funName."(parameter:";//Printthemethod'snamethatisnotexisted.print_r($arguments);//Printtheparameterlistofthemethodthatisnotexisted.echo")doesnotexist!!<br>\n";}}$Person=newPerson();$Person->run("teacher");//Ifthemethodwhichisnotexistediscalledwithintheobject,thenthe__call()methodwillbecalledautomatically.$Person->eat("John","apple");$Person->say();

显示结果

Thefunctionyoucalled:run(parameter:Array([0]=>teacher))doesnotexist!Thefunctionyoucalled:eat(parameter:Array([0]=>John[1]=>apple))doesnotexist!Helloworld!

4. __callStatic()

当在程序中调用未定义的静态方法,__callStatic()方法将会被自动调用。

__callStatic()的用法类似于__call()。下面举个例子:

<?phpclassPerson{functionsay(){echo"Hello,world!<br>";}publicstaticfunction__callStatic($funName,$arguments){echo"Thestaticmethodyoucalled:".$funName."(parameter:";//打印出未定义的方法名。print_r($arguments);//打印出未定义方法的参数列表。echo")doesnotexist!<br>\n";}}$Person=newPerson();$Person::run("teacher");//如果此项目内不存在的方法被调用了,那么__callStatic()方法将被自动调用。$Person::eat("John","apple");$Person->say();

执行结果如下:

Thestaticmethodyoucalled:run(parameter:Array([0]=>teacher))doesnotexist!Thestaticmethodyoucalled:eat(parameter:Array([0]=>John[1]=>apple))doesnotexist!Helloworld!

5. __get()

当你尝试在外部访问对象的私有属性时,应用程序将抛出异常并结束运行。我们可以使用__get方法解决该问题。该方法可以获取从对象外部获取私有属性的值。举例如下

<?phpclassPerson{private$name;private$age;function__construct($name="",$age=1){$this->name=$name;$this->age=$age;}publicfunction__get($propertyName){if($propertyName=="age"){if($this->age>30){return$this->age-10;}else{return$this->$propertyName;}}else{return$this->$propertyName;}}}$Person=newPerson("John",60);//InstantiatetheobjectwiththePersonclassandassigninitialvaluestothepropertieswiththeconstructor.echo"Name:".$Person->name."<br>";//Whentheprivatepropertyisaccessed,the__get()methodwillbecalledautomatically,sowecangetthepropertyvalueindirectly.echo"Age:".$Person->age."<br>";//The__get()methodiscalledautomatically,anditreturnsdifferentvaluesaccordingtotheobjectitself.

结果显示如下

Name:JohnAge:50

6. __set()

set($property,$value)方法用于设置类的私有属性。分配了未定义的属性后,将触发set()方法,并且传递的参数是设置的属性名称和值。

下面是演示代码:

<?phpclassPerson{private$name;private$age;publicfunction__construct($name="",$age=25){$this->name=$name;$this->age=$age;}publicfunction__set($property,$value){if($property=="age"){if($value>150||$value<0){return;}}$this->$property=$value;}publicfunctionsay(){echo"Mynameis".$this->name.",I'm".$this->age."yearsold";}}$Person=newPerson("John",25);//请注意,类初始化并为“name”和“age”分配初始值。$Person->name="Lili";//"name"属性值被成功修改。如果没有__set()方法,程序将报错。$Person->age=16;//"age"属性修改成功。$Person->age=160;//160是无效值,因此修改失败。$Person->say();//输出:MynameisLili,I'm16yearsold。

代码运行结果:

MynameisLili,I'm16yearsold

7. __isset()

在使用__isset()方法之前,让我先解释一下isset()方法的用法。isset()方法主要用于确定是否设置了此变量。

如果在对象外部使用isset()方法,则有两种情况:

如果该参数是公共属性,则可以使用isset()方法确定是否设置了该属性。

如果参数是私有属性,则isset()方法将不起作用。

那么对于私有属性,有什么办法知道它是否被设置了吗?当然,只要在类中定义__isset()方法,就可以在类外部使用isset()方法来确定是否设置了私有属性。

当在未定义或不可访问的属性上调用isset()或empty()时,将调用__isset()方法。下面是一个例子:

<?phpclassPerson{public$sex;private$name;private$age;publicfunction__construct($name="",$age=25,$sex='Male'){$this->name=$name;$this->age=$age;$this->sex=$sex;}/***@param$content**@returnbool*/publicfunction__isset($content){echo"The{$content}propertyisprivate,the__isset()methodiscalledautomatically.<br>";echoisset($this->$content);}}$person=newPerson("John",25);//Initiallyassigned.echoisset($person->sex),"<br>";echoisset($person->name),"<br>";echoisset($person->age),"<br>";

代码运行结果如下:

1Thenamepropertyisprivate,the__isset()methodiscalledautomatically.1Theagepropertyisprivate,the__isset()methodiscalledautomatically.1

8. __unset()

与isset()方法类似,当在未定义或不可访问的属性上调用unset()方法时,将调用unset()方法。下面是一个例子:

<?phpclassPerson{public$sex;private$name;private$age;publicfunction__construct($name="",$age=25,$sex='Male'){$this->name=$name;$this->age=$age;$this->sex=$sex;}/***@param$content**@returnbool*/publicfunction__unset($content){echo"Itiscalledautomaticallywhenweusetheunset()methodoutsidetheclass.<br>";echoisset($this->$content);}}$person=newPerson("John",25);//Initiallyassigned.unset($person->sex),"<br>";unset($person->name),"<br>";unset($person->age),"<br>";

代码的运行结果如下:

Itiscalledautomaticallywhenweusetheunset()methodoutsidetheclass.1Itiscalledautomaticallywhenweusetheunset()methodoutsidetheclass.1

9. __sleep()

serialize()方法将检查类中是否有魔术方法__sleep()。如果存在,将首先调用该方法,然后执行序列化操作。

__sleep()方法通常用于指定保存数据之前需要序列化的属性。如果有一些非常大的对象不需要全部保存,那么您会发现此功能非常有用。

有关详细信息,请参考以下代码:

<?phpclassPerson{public$sex;public$name;public$age;publicfunction__construct($name="",$age=25,$sex='Male'){$this->name=$name;$this->age=$age;$this->sex=$sex;}/***@returnarray*/publicfunction__sleep(){echo"Itiscalledwhentheserialize()methodiscalledoutsidetheclass.<br>";$this->name=base64_encode($this->name);returnarray('name','age');//Itmustreturnavalueofwhichtheelementsarethenameofthepropertiesreturned.}}$person=newPerson('John');//Initiallyassigned.echoserialize($person);echo'<br/>';

代码运行结果如下:

Itiscalledwhentheserialize()methodiscalledoutsidetheclass.O:6:"Person":2:{s:4:"name";s:8:"5bCP5piO";s:3:"age";i:25;}

10. __wakeup()

与sleep()方法相比,wakeup()方法通常用于反序列化操作,例如重建数据库连接或执行其他初始化操作。

下面是相关实例:

<?phpclassPerson{public$sex;public$name;public$age;publicfunction__construct($name="",$age=25,$sex='Male'){$this->name=$name;$this->age=$age;$this->sex=$sex;}/***@returnarray*/publicfunction__sleep(){echo"Itiscalledwhentheserialize()methodiscalledoutsidetheclass.<br>";$this->name=base64_encode($this->name);returnarray('name','age');//Itmustreturnavalueofwhichtheelementsarethenameofthepropertiesreturned.}/***__wakeup*/publicfunction__wakeup(){echo"Itiscalledwhentheunserialize()methodiscalledoutsidetheclass.<br>";$this->name=2;$this->sex='Male';//Thereisnoneedtoreturnanarrayhere.}}$person=newPerson('John');//Initiallyassigned.var_dump(serialize($person));var_dump(unserialize(serialize($person)));

代码运行结果如下:

Itiscalledwhentheserialize()methodiscalledoutsidetheclass.string(58)"O:6:"Person":2:{s:4:"name";s:8:"5bCP5piO";s:3:"age";i:25;}"Itiscalledwhentheunserialize()methodiscalledoutsidetheclass.object(Person)#2(3){["sex"]=>string(3)"Male"["name"]=>int(2)["age"]=>int(25)}

11. __toString()

使用echo方法直接打印对象时,将调用__toString()方法。

注意:此方法必须返回一个字符串,否则将在E_RECOVERABLE_ERROR级别上引发致命错误。而且您也不能在__toString()方法中抛出异常。

下面是相关的实例:

<?phpclassPerson{public$sex;public$name;public$age;publicfunction__construct($name="",$age=25,$sex='Male'){$this->name=$name;$this->age=$age;$this->sex=$sex;}publicfunction__toString(){return'gogogo';}}$person=newPerson('John');//Initiallyassigned.echo$person;

运行代码结果如下:

gogogo

那么,如果在类中未定义__toString()方法怎么办?让我们尝试一下。

<?phpclassPerson{public$sex;public$name;public$age;publicfunction__construct($name="",$age=25,$sex='Male'){$this->name=$name;$this->age=$age;$this->sex=$sex;}}$person=newPerson('John');//Initiallyassigned.echo$person;

运行代码结果如下:

Catchablefatalerror:ObjectofclassPersoncouldnotbeconvertedtostringinD:\phpStudy\WWW\test\index.phponline18

显然,它在页面上报告了一个致命错误,PHP语法不支持这样的写法。

12. __invoke()

当您尝试以调用函数的方式调用对象时,__ invoke()方法将被自动调用。

注意:此功能仅在PHP 5.3.0及更高版本中有效。

下面是相关实例:

<?phpclassPerson{public$sex;public$name;public$age;publicfunction__construct($name="",$age=25,$sex='Male'){$this->name=$name;$this->age=$age;$this->sex=$sex;}publicfunction__invoke(){echo'Thisisanobject';}}$person=newPerson('John');//Initiallyassigned.$person();

运行代码结果如下:

Thisisanobject

如果坚持使用对象作为方法(但未定义__invoke()方法),则将得到以下结果:

Fatalerror:FunctionnamemustbeastringinD:\phpStudy\WWW\test\index.phponline18

13.__set_state()

从PHP 5.1.0开始,在调用var_export()导出类代码时会自动调用__set_state()方法。

__set_state()方法的参数是一个包含所有属性值的数组,其格式为array('property'=> value,…)

在以下示例中,我们没有定义__set_state()方法:

<?phpclassPerson{public$sex;public$name;public$age;publicfunction__construct($name="",$age=25,$sex='Male'){$this->name=$name;$this->age=$age;$this->sex=$sex;}}$person=newPerson('John');//Initiallyassigned.var_export($person);

执行代码结果如下:

Person::__set_state(array('sex'=>'Male','name'=>'John','age'=>25,))

显然,对象的属性已打印。

现在让我们看看定义__set_state()方法的另一种情况:

<?phpclassPerson{public$sex;public$name;public$age;publicfunction__construct($name="",$age=25,$sex='Male'){$this->name=$name;$this->age=$age;$this->sex=$sex;}publicstaticfunction__set_state($an_array){$a=newPerson();$a->name=$an_array['name'];return$a;}}$person=newPerson('John');//Initiallyassigned.$person->name='Jams';var_export($person);

执行代码结果如下:

Person::__set_state(array('sex'=>'Male','name'=>'Jams','age'=>25,))

14. __clone()

在PHP中,我们可以使用clone关键字通过以下语法克隆对象:

$copy_of_object=clone$object;

但是,使用clone关键字只是一个浅拷贝,因为所有引用的属性仍将指向原始变量。

如果在对象中定义了clone()方法,则将在复制生成的对象中调用clone()方法,该方法可用于修改属性的值(如有必要)。

下面是相关的示例:

<?phpclassPerson{public$sex;public$name;public$age;publicfunction__construct($name="",$age=25,$sex='Male'){$this->name=$name;$this->age=$age;$this->sex=$sex;}publicfunction__clone(){echo__METHOD__."yourarecloningtheobject.<br>";}}$person=newPerson('John');//Initiallyassigned.$person2=clone$person;var_dump('persion1:');var_dump($person);echo'<br>';var_dump('persion2:');var_dump($person2);

运行代码结果如下:

Person::__cloneyourarecloningtheobject.string(9)"persion1:"object(Person)#1(3){["sex"]=>string(3)"Male"["name"]=>string(6)"John"["age"]=>int(25)}string(9)"persion2:"object(Person)#2(3){["sex"]=>string(3)"Male"["name"]=>string(6)"John"["age"]=>int(25)}

15.__autoload()

__autoload()方法可以尝试加载未定义的类。

过去,如果要在程序文件中创建100个对象,则必须使用include()或require()来包含100个类文件,或者必须在同一类文件中定义100个类。 例如以下:

/***filenon_autoload.php*/require_once('project/class/A.php');require_once('project/class/B.php');require_once('project/class/C.php');…if(ConditionA){$a=newA();$b=newB();$c=newC();//…}elseif(ConditionB){$a=newA();$b=newB();//…}

那么,如果我们使用__autoload()方法呢?

/***fileautoload_demo.php*/function__autoload($className){$filePath=“project/class/{$className}.php”;if(is_readable($filePath)){require($filePath);}}if(ConditionA){$a=newA();$b=newB();$c=newC();//…}elseif(ConditionB){$a=newA();$b=newB();//…}

当PHP引擎第一次使用类A时,如果未找到类A,则autoload方法将被自动调用,并且类名称“ A”将作为参数传递。因此,我们在autoload()方法中需要做的是根据类名找到相应的类文件,然后将其包含在内。如果找不到该文件,则php引擎将抛出异常。

16. __debugInfo()

当执行var_dump()方法时,__debugInfo()方法会被自动调用。如果__debugInfo()方法未被定义,那么var_dump方法或打印出这个对象的所有属性。

举例说明:

<?phpclassC{private$prop;publicfunction__construct($val){$this->prop=$val;}/***@returnarray*/publicfunction__debugInfo(){return['propSquared'=>$this->prop**2,];}}var_dump(newC(42));

执行结果:

object(C)#1(1){["propSquared"]=>int(1764)}

注意:__debugInfo() 方法应该在 PHP 5.6.0 及以上版本中使用。

总结

以上就是我所了解的PHP魔术方法,其中常用的包括__set()还有__get()和__autoload()。如果你还有其他疑问,可以从PHP官方网站获得更多帮助。

原文地址:https://www.tutorialdocs.com/article/16-php-magic-methods.html

译文地址:https://learnku.com/php/t/40919

产品猿社区致力收录更多优质的商业产品,给服务商以及软件采购客户提供更多优质的软件产品,帮助开发者变现来实现多方共赢;

日常运营的过程中我们难免会遇到各种版权纠纷等问题,如果您在社区内发现有您的产品未经您授权而被用户提供下载或使用,您可按照我们投诉流程处理,点我投诉

本文来自用户发布投稿,不代表产品猿立场 ;若对此文有疑问或内容有严重错误,可联系平台客服反馈;

部分产品是用户投稿,可能本文没有提供官方下下载地址或教程,若您看到的内容没有下载入口,您可以在我们产品园商城搜索看开发者是否有发布商品;若您是开发者,也诚邀您入驻商城平台发布的产品,地址:点我进入

如若转载,请注明出处:https://www.chanpinyuan.cn/28328.html;
(0)
上一篇 2022年12月1日 下午4:18
下一篇 2022年12月3日 下午4:17

相关推荐

发表回复

登录后才能评论
分享本页
返回顶部