本教程操作环境:windows7系统、PHP8版、DELL G3电脑
(资料图)
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]){ 方法具体实现 //通常为成员变量初始赋值。}
登录后复制
下面是个完整的例子:
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}
登录后复制
析构函数的使用
析构函数在类中一般不常见。它是类的可选部分,通常用于在类销毁之前完成一些清理任务。
这是使用析构函数的示例:
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()
方法将被调用。
示例
"; } 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!!
\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()
。下面举个例子:
"; } public static function __callStatic($funName, $arguments) { echo "The static method you called:" . $funName . "(parameter:" ; // 打印出未定义的方法名。 print_r($arguments); // 打印出未定义方法的参数列表。 echo ")does not exist!
\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
方法解决该问题。该方法可以获取从对象外部获取私有属性的值。举例如下
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 . "
"; // 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 . "
"; // The __get() method is called automatically,and it returns different values according to the object itself.
登录后复制
结果显示如下
Name: JohnAge: 50
登录后复制
6. __set()
set($property,$value)方法用于设置类的私有属性。分配了未定义的属性后,将触发set()方法,并且传递的参数是设置的属性名称和值。
下面是演示代码:
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()方法。下面是一个例子:
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.
"; echo isset($this->$content); }}$person = new Person("John", 25); // Initially assigned.echo isset($person->sex),"
";echo isset($person->name),"
";echo isset($person->age),"
";
登录后复制
代码运行结果如下:
1The name property is private,the __isset() method is called automatically.1The age property is private,the __isset() method is called automatically.1
登录后复制
8. __unset()
与isset()方法类似,当在未定义或不可访问的属性上调用unset()方法时,将调用unset()方法。下面是一个例子:
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.
"; echo isset($this->$content); }}$person = new Person("John", 25); // Initially assigned.unset($person->sex),"
";unset($person->name),"
";unset($person->age),"
";
登录后复制
代码的运行结果如下:
It is called automatically when we use the unset() method outside the class.1It is called automatically when we use the unset() method outside the class.1
登录后复制
9. __sleep()
serialize()方法将检查类中是否有魔术方法__sleep()。如果存在,将首先调用该方法,然后执行序列化操作。
__sleep()方法通常用于指定保存数据之前需要序列化的属性。如果有一些非常大的对象不需要全部保存,那么您会发现此功能非常有用。
有关详细信息,请参考以下代码:
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.
"; $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 "
";
登录后复制
代码运行结果如下:
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()方法通常用于反序列化操作,例如重建数据库连接或执行其他初始化操作。
下面是相关实例:
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.
"; $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.
"; $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()方法中抛出异常。
下面是相关的实例:
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()方法怎么办?让我们尝试一下。
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()方法将被自动调用。
下面是相关实例:
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 18
登录后复制
13.__set_state()
从PHP 5.1.0开始,在调用var_export()导出类代码时会自动调用__set_state()方法。
__set_state()方法的参数是一个包含所有属性值的数组,其格式为array("property"=> value,...)
在以下示例中,我们没有定义__set_state()方法:
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()方法的另一种情况:
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()方法,该方法可用于修改属性的值(如有必要)。
下面是相关的示例:
name = $name; $this->age = $age; $this->sex = $sex; } public function __clone() { echo __METHOD__."your are cloning the object.
"; }}$person = new Person("John"); // Initially assigned.$person2 = clone $person;var_dump("persion1:");var_dump($person);echo "
";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
方法或打印出这个对象的所有属性。
举例说明:
prop = $val; } /** * @return array */ public function __debugInfo() { return [ "propSquared" => $this->prop ** 2, ]; }}var_dump(new C(42));
登录后复制
执行结果:
object(C)#1 (1) { ["propSquared"]=> int(1764) }
登录后复制
总结
以上就是我所了解的 PHP
魔术方法,其中常用的包括 __set()
还有 __get()
和 __autoload()
。如果你还有其他疑问,可以从 PHP
官方网站获得更多帮助。
推荐学习:《PHP视频教程》
以上就是php魔术方法是什么的详细内容,更多请关注php中文网其它相关文章!