您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > php

16 个 PHP 开发者必知必会的魔术方法

时间:2020-09-04 10:11:52  来源:  作者:

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

16 个 PHP 开发者必知必会的魔术方法

 

本文将使用一些实例展示 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: 50

6. __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 old

7. __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.
1

8. __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.
1

9. __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:phpStudyWWWtestindex.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:phpStudyWWWtestindex.php on line 18

13.__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 魔术方法,其中常用的包括 __set() 还有 __get() 和 __autoload()。如果你还有其他疑问,可以从 PHP 官方网站获得更多帮助。



Tags:PHP 开发   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
在 PHP 中,以双下划线(__)开始命名的方法被称作 PHP 中的魔术方法,它们在 PHP 中充当很重要的角色。魔术方法包括: 本文将使用一些实例展示 PHP 魔术方法的运用。 1.__construct(...【详细内容】
2020-09-04  Tags: PHP 开发  点击:(61)  评论:(0)  加入收藏
▌简易百科推荐
序言:前段时间织梦因为版权的问题在网上闹得沸沸扬扬,也提醒了众多开发者选择cms上应该谨慎使用,今天给大家展示一款自己搭建的内容管理系统,不用担心版权的问题,而且非常容易维...【详细内容】
2021-11-30  小程序软件开发    Tags:管理系统   点击:(31)  评论:(0)  加入收藏
准备安装包(PHP: Hypertext Preprocessor)下载安装包以及组件wget https://www.php.net/distributions/php-8.0.0.tar.bz2wget https://github.com/phpredis/phpredis/archive...【详细内容】
2021-11-09  mimic96    Tags:PHP   点击:(40)  评论:(0)  加入收藏
golang context 很好用,就使用php实现了github地址 : https://github.com/qq1060656096/php-go-context context使用闭坑指南1. 将一个Context参数作为第一个参数传递给传入和...【详细内容】
2021-11-05  1060656096    Tags:PHP   点击:(40)  评论:(0)  加入收藏
一段数组为例:$list = array:4 [ 0 => array:7 [ "id" => 56 "mer_id" => 7 "order_id" => "wx163265961408769974" "is_postage" => 0 "store_name" => "奇...【详细内容】
2021-09-29  七七小影视    Tags:PHP   点击:(64)  评论:(0)  加入收藏
利用JS的CryptoJS 3.x和PHP的openssl_encrypt,openssl_decrypt实现AES对称加密解密,由于需要两种语言对同一字符串的操作,而CryptoJS 的默认加密方式为“aes-256-cbc”,PHP端也...【详细内容】
2021-09-16  李老师tome    Tags:对称加密   点击:(79)  评论:(0)  加入收藏
1、checkdate()验证格利高里日期即:日期是否存在。checkdate(month,day,year);month必需。一个从 1 到 12 的数字,规定月。day必需。一个从 1 到 31 的数字,规定日。year必需。...【详细内容】
2021-08-31  七七小影视    Tags:时间函数   点击:(80)  评论:(0)  加入收藏
对于各类开发语言来说,整数都有一个最大的位数,如果超过位数就无法显示或者操作了。其实,这也是一种精度越界之后产生的精度丢失问题。在我们的 PHP 代码中,最大的整数非常大,我...【详细内容】
2021-08-26  硬核项目经理    Tags:PHP   点击:(83)  评论:(0)  加入收藏
遵从所有教材以及各类数据结构相关的书书籍,我们先从线性表开始入门。今天这篇文章更偏概念,是关于有线性表的一个知识点的汇总。上文说过,物理结构是用于确定数据以何种方式存...【详细内容】
2021-07-19  硬核项目经理    Tags:线性表   点击:(94)  评论:(0)  加入收藏
一、开启IIS全部功能。二、部署PHP1.官网下载并解压PHP: https://windows.php.net/downloads/releases/2.将php.ini-development文件改为php.ini3.修改php.ini(1)去掉注释,并修...【详细内容】
2021-07-15  炘蓝火诗  今日头条  Tags:PHP环境   点击:(128)  评论:(0)  加入收藏
一、环境说明本文中使用本地VM虚机部署测试。OS:CentOS Linux release 7.8.2003 (Core)虚机配置:2核CPU、4G内存①系统为CentOS 7.8 x64最小化安装,部署前已完成系统初始化、...【详细内容】
2021-06-25  IT运维笔记  今日头条  Tags:PHP8.0.7   点击:(141)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条