带你吃透16个PHP魔术方法

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

什么是魔术方法?本篇文章带大家了解一下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([parameter list]){

方法具体实现 //通常为成员变量初始赋值。

}

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

下面是个完整的例子:

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

/**
* 明确定义含参的构造方法
*/
public function __construct($name=;;, $sex=;Male;, $age=22)
{
$this->name = $name;
$this->sex = $sex;
$this->age = $age;
}

/**
* say 方法定义
*/
public function say()
{
echo ;Name:; . $this->name . ;,Sex:; . $this->sex . ;,Age:; . $this->age;
}

}

无参创建 $Person1 对象。

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

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

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

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

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

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

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

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

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

析构函数的声明function __destruct()
{
//method body
}

析构函数不能带参数。

析构函数的使用

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

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

<?php
class Person{

public $name;
public $age;
public $sex;

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

/**
* say method
*/
public function say()
{
echo ;Name:;.$this->name.;,Sex:;.$this->sex.;,Age:;.$this->age;
}

/**
* declare a destructor method
*/
public function __destruct()
{
echo ;Well, my name is ;.$this->name;
}
}

$Person = new Person(;John;);
unset($Person); //destroy the object of $Person created above

输出结果

Well, my name is John__call()

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

使用function __call(string $function_name, array $arguments)
{
// method body
}

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

示例

<?php
class Person
{
function say()
{
echo ;Hello, world!<br>;;
}

function __call($funName, $arguments)
{
echo ;The function you called:; . $funName . ;(parameter:; ; // Print the method;s name that is not existed.
print_r($arguments); // Print the parameter list of the method that is not existed.
echo ;)does not exist!!<br>\n;;
}
}
$Person = new Person();
$Person->run(;teacher;); // If the method which is not existed is called within the object, then the __call() method will be called automatically.
$Person->eat(;John;, ;apple;);
$Person->say();

显示结果

The function you called: run (parameter: Array([0] => teacher)) does not exist!
The function you called: eat (parameter: Array([0] => John[1] => apple)) does not exist!
Hello world!4. __callStatic()

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

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

<?php
class Person
{
function say()
{
echo ;Hello, world!<br>;;
}

public static function __callStatic($funName, $arguments)
{
echo ;The static method you called:; . $funName . ;(parameter:; ; // 打印出未定义的方法名。
print_r($arguments); // 打印出未定义方法的参数列表。
echo ;)does not exist!<br>\n;;
}
}
$Person = new Person();
$Person::run(;teacher;); // 如果此项目内不存在的方法被调用了,那么 __callStatic() 方法将被自动调用。
$Person::eat(;John;, ;apple;);
$Person->say();

执行结果如下:

The static method you called: run (parameter: Array([0] => teacher)) does not exist!
The static method you called: eat (parameter: Array([0] => John[1] => apple)) does not exist!
Hello world!__get()

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

<?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(;John;, 60); // Instantiate the object with the Person class and assign initial values to the properties with the constructor.
echo ;Name:; . $Person->name . ;<br>;; // When the private property is accessed, the __get() method will be called automatically,so we can get the property value indirectly.
echo ;Age:; . $Person->age . ;<br>;; // The __get() method is called automatically,and it returns different values according to the object itself.

结果显示如下

Name: John
Age: 506. __set()

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

下面是演示代码:

<?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 ;My name is ;.$this->name.;,I;m ;.$this->age.; years old;;
}
}

$Person=new Person(;John;, 25); //请注意,类初始化并为“name”和“age”分配初始值。
$Person->name = ;Lili;; // ;name; 属性值被成功修改。如果没有__set()方法,程序将报错。
$Person->age = 16; // ;age;属性修改成功。
$Person->age = 160; //160是无效值,因此修改失败。
$Person->say(); //输出:My name is Lili, I;m 16 years old。

代码运行结果:

My name is Lili, I;m 16 years old7. __isset()

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

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

  • 如果该参数是公共属性,则可以使用isset()方法确定是否设置了该属性。
  • 如果参数是私有属性,则isset()方法将不起作用。
  • 那么对于私有属性,有什么办法知道它是否被设置了吗?当然,只要在类中定义__isset()方法,就可以在类外部使用isset()方法来确定是否设置了私有属性。

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

    <?php
    class Person
    {
    public $sex;
    private $name;
    private $age;

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

    /**
    * @param $content
    *
    * @return bool
    */
    public function __isset($content) {
    echo ;The {$content} property is private,the __isset() method is called automatically.<br>;;
    echo isset($this->$content);
    }
    }

    $person = new Person(;John;, 25); // Initially assigned.
    echo isset($person->sex),;<br>;;
    echo isset($person->name),;<br>;;
    echo isset($person->age),;<br>;;

    代码运行结果如下:

    1
    The name property is private,the __isset() method is called automatically.
    1
    The age property is private,the __isset() method is called automatically.
    18. __unset()

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

    <?php
    class Person
    {
    public $sex;
    private $name;
    private $age;

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

    /**
    * @param $content
    *
    * @return bool
    */
    public function __unset($content) {
    echo ;It is called automatically when we use the unset() method outside the class.<br>;;
    echo isset($this->$content);
    }
    }

    $person = new Person(;John;, 25); // Initially assigned.
    unset($person->sex),;<br>;;
    unset($person->name),;<br>;;
    unset($person->age),;<br>;;

    代码的运行结果如下:

    It is called automatically when we use the unset() method outside the class.
    1
    It is called automatically when we use the unset() method outside the class.
    19. __sleep()

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

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

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

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

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

    /**
    * @return array
    */
    public function __sleep() {
    echo ;It is called when the serialize() method is called outside the class.<br>;;
    $this->name = base64_encode($this->name);
    return array(;name;, ;age;); // It must return a value of which the elements are the name of the properties returned.
    }
    }

    $person = new Person(;John;); // Initially assigned.
    echo serialize($person);
    echo ;<br/>;;

    代码运行结果如下:

    It is called when the serialize() method is called outside the class.
    O:6:;Person;:2:{s:4:;name;;s:8:;5bCP5piO;;s:3:;age;;i:25;}10. __wakeup()

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

    下面是相关实例:

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

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

    /**
    * @return array
    */
    public function __sleep() {
    echo ;It is called when the serialize() method is called outside the class.<br>;;
    $this->name = base64_encode($this->name);
    return array(;name;, ;age;); // It must return a value of which the elements are the name of the properties returned.
    }

    /**
    * __wakeup
    */
    public function __wakeup() {
    echo ;It is called when the unserialize() method is called outside the class.<br>;;
    $this->name = 2;
    $this->sex = ;Male;;
    // There is no need to return an array here.
    }
    }

    $person = new Person(;John;); // Initially assigned.
    var_dump(serialize($person));
    var_dump(unserialize(serialize($person)));

    代码运行结果如下:

    It is called when the serialize() method is called outside the class.
    string(58) ;O:6:;Person;:2:{s:4:;name;;s:8:;5bCP5piO;;s:3:;age;;i:25;};
    It is called when the unserialize() method is called outside the class.
    object(Person)#2 (3) { [;sex;]=> string(3) ;Male; [;name;]=> int(2) [;age;]=> int(25) }11. __toString()

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

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

    下面是相关的实例:

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

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

    public function __toString()
    {
    return ;go go go;;
    }
    }

    $person = new Person(;John;); // Initially assigned.
    echo $person;

    运行代码结果如下:

    go go go

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

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

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

    }

    $person = new Person(;John;); // Initially assigned.
    echo $person;

    运行代码结果如下:

    Catchable fatal error: Object of class Person could not be converted to string in D:\phpStudy\WWW\test\index.php on line 18

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

    12. __invoke()

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

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

    下面是相关实例:

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

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

    public function __invoke() {
    echo ;This is an object;;
    }

    }

    $person = new Person(;John;); // Initially assigned.
    $person();

    运行代码结果如下:

    This is an object

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

    Fatal error: Function name must be a string in D:\phpStudy\WWW\test\index.php on line 1813.__set_state()

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

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

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

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

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

    }

    $person = new Person(;John;); // Initially assigned.
    var_export($person);

    执行代码结果如下:

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

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

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

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

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

    public static function __set_state($an_array)
    {
    $a = new Person();
    $a->name = $an_array[;name;];
    return $a;
    }

    }

    $person = new Person(;John;); // Initially assigned.
    $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()方法,该方法可用于修改属性的值(如有必要)。

    下面是相关的示例:

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

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

    public function __clone()
    {
    echo __METHOD__.;your are cloning the object.<br>;;
    }

    }

    $person = new Person(;John;); // Initially assigned.
    $person2 = clone $person;

    var_dump(;persion1:;);
    var_dump($person);
    echo ;<br>;;
    var_dump(;persion2:;);
    var_dump($person2);

    运行代码结果如下:

    Person::__clone your are cloning the object.
    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个类。 例如以下:

    /**
    * file non_autoload.php
    */

    require_once(;project/class/A.php;);
    require_once(;project/class/B.php;);
    require_once(;project/class/C.php;);
    .
    .
    .

    if (ConditionA) {
    $a = new A();
    $b = new B();
    $c = new C();
    // …
    } else if (ConditionB) {
    $a = newA();
    $b = new B();
    // …
    }

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

    /**
    * file autoload_demo.php
    */
    function __autoload($className) {
    $filePath = “project/class/{$className}.php”;
    if (is_readable($filePath)) {
    require($filePath);
    }
    }

    if (ConditionA) {
    $a = new A();
    $b = new B();
    $c = new C();
    // …
    } else if (ConditionB) {
    $a = newA();
    $b = new B();
    // …
    }

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

    16. __debugInfo()

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

    举例说明:

    <?php
    class C {
    private $prop;

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

    /**
    * @return array
    */
    public function __debugInfo() {
    return [
    ;propSquared; => $this->prop ** 2,
    ];
    }
    }

    var_dump(new C(42));

    执行结果:

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

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

    总结

    php魔术方法有哪些

    php魔术方法:1、【_sleep()】控制对象序列化时真正处理的部分;2、【_wakeup()】在反序列化后还原对象属性;3、【_toString()】对象转换成为字符串的机制。

    带你吃透16个PHP魔术方法

    本教程操作环境:windows7系统、PHP5.6版,DELL G3电脑。

    php魔术方法:

    _sleep() 可以控制对象序列化时真正处理的部分

    _wakeup() 在反序列化后还原对象属性

    _toString() 对象转换成为字符串的机制

    php变量转换成一串编码后字符串,方法为serialize() 反序列化unserialize()

    //序列化
    class testSerialize{
    public $a = 10;
    public $b = 15;
    public $c = 20;
    function _construct(){
    $this->b = $this->a * 10;
    $this->c = $this->b * 2;
    }
    }
    $k = serialize(new testSerialize());
    echo $k;//
    out: O:13:"testSerialize":3:{s:1:"a";i:10;s:1:"b";i:15;s:1:"c";i:20;}
    $j = unserialize($k);

    sleep方法:

    class testSerialize1{
    public $a = 10;
    public $b = 15;
    public $c = 20;
    function _construct(){
    $this->b = $this->a * 10;
    $this->c = $this->b * 2;
    }
    function __sleep(){
    return $this->a;
    }
    }
    $k = serialize(new testSerialize1());
    echo $k;

    其他方法同理

    以上就是php魔术方法有哪些的详细内容,更多请关注钦钦技术栈其它相关文章!

    转载至:php中文网【www.php.cn】

    版权声明:本文(即:原文链接:https://www.qin1qin.com/catagory/23464/)内容由互联网用户自发投稿贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 630367839@qq.com 举报,一经查实,本站将立刻删除。

    (0)
    上一篇 2022-09-19 12:54:17
    下一篇 2022-09-19 12:55:36

    软件定制开发公司

    相关阅读

    发表回复

    登录后才能评论
    通知:禁止投稿所有关于虚拟货币,币圈类相关文章,发现立即永久封锁账户ID!