PHP 的魔术方法及其应用
PHP中将所有__(两个下划线)开头的类方法作为魔术方法,这方法之所以称为魔术方法是因为其实现的功能就如变魔术一样感觉很神奇。在特定的事件下触发,这真的很酷。
__construct()
这个方法应该是最常用的,被称为构造器或者构造方法,当一个对象被实例化时会被首先调用,而在 PHP 框架中一些过滤器,中间件及依赖注入也一般在这个方法中完成。父类的构造器可以被子类继承和重写。
<?php
class A {
public function __construct() {
echo "This is A construct\n";
}
}
class B extends A{
// 调用父类构造方法,再调用自己的构造方法
public function __construct() {
parent::__construct();
echo "This is B construct\n";
}
}
class C extends A{
// 重写构造方法,之调用自己的构造方法
public function __construct() {
echo "This is C construct";
}
}
new A();// This is A construct
new B();// This is A construct This is B construct
new C();// This is c construct
以上示例代码将按顺序输出:
This is A construct
This is A construct
This is B construct
This is C construct
构造方法能帮助我们完成一些数据初始化,属性初始化的任务,在实例化类后使得调用类更便利。
__destruct()
析构方法,PHP 将对象销毁前将调用这个方法,这个方法可能对于 PHP 这种运行时间短的脚本可能无意义,但在有些情况下还是具有意义的。
比如你需要一个长时间运行的脚本,设置 set_time_limit(0);
后需要不断执行这个脚本,一般这样的脚本是循环执行一些任务,这其中可能会涉及到频繁的创建某个对象,这时候析构方法就会起到作用,它可以将对象打开的一些资源及时的释放,以防止内存溢出或单个进程占用过多内存。
<?php
class Log{
public function __construct() {
$this->created = time();
$this->logfile_handle = fopen('/tmp/log.txt', 'w');
}
public function __destruct() {
fclose($this->logfile_handle);
}
}
__get()与__set()
这两个方法的作用是当调用或设置一个类及其父类方法中未定义的属性时这个方法会被触发。
<?php
class MethodTest
{
private $data = array();
public function __set($name, $value){
$this->data[$name] = $value;
}
public function __get($name){
if(array_key_exists($name, $this->data))
return $this->data[$name];
return NULL;
}
}
class Penguin extends Animal {
public function __construct($id) {
$this->getPenguinFromDb($id);
}
public function getPenguinFromDb($id) {
// elegant and robust database code goes here
}
public function __get($field) {
if($field == 'name') {
return $this->username;
}
}
public function __set($field, $value) {
if($field == 'name') {
$this->username = $value;
}
}
}
在 MethodTest 这个类中使用 __get 和 __set 将所有不存在的属性都保存在类的 data 属性中,而在Penguin 类中我们连接了数据库或者是数据提供者,由于某些原因数据源中原来的 name 变更为 username ,如果这时要检查所有调用 Penguin 类的地方将 name 换成 username 显然是困难而且无趣的甚至会有忽略的地方,而使用一个 __get 方法我们不用改变外部调用的属性名就可以实现从 name 转变为 username
__call 和 __callStatic
__call 和 __callStatic 是类似的方法,前者是调用类不存在的方法时执行,而后者是调用类不存在的静态方式方法时执行。正常情况下如果调用一个类不存在的方法 PHP 会抛出致命错误,而使用这两个魔术方法我们可以替换一些更友好的提示或者记录错误调用日志信息、将用户重定向、抛出异常等等,亦或者是如同__set 和 __get 那样做方法的重命名。
class A
{
public static function __callStatic($name, $arguments)
{
var_dump($name);
var_dump($arguments);
echo 'unknown static method ' . $name;
}
function __call($name, $arguments)
{
var_dump($name);
var_dump($arguments);
echo 'unknown method ' . $name;
}
}
$a = new A();
$a->agfdgdrsfgdf([123,3213]);
A::sdfsd();
__sleep() 和 __wakeup()
当我们执行 serialize()
和 unserialize()
对对象进行操作是时,会调用这两个方法,比如对象有一个数据库链接,想要在反序列化时恢复链接状态,而在序列化时希望将属性键名保存就可以使用这两个魔术方法:
<?php
class Connection
{
protected $link;
private $server, $username, $password, $db;
public function __construct($server, $username, $password, $db)
{
$this->server = $server;
$this->username = $username;
$this->password = $password;
$this->db = $db;
$this->connect();
}
private function connect()
{
$this->link = mysql_connect($this->server, $this->username, $this->password);
mysql_select_db($this->db, $this->link);
}
public function __sleep()
{
return array('server', 'username', 'password', 'db');
}
public function __wakeup()
{
$this->connect();
}
}
__clone()
如同名字一样,这个方法在对象被复制是调用,如我们要实现一个单例模式,我们可以用这个魔术方法防止对象被克隆。
<?php
public class Singleton {
private static $_instance = NULL;
// 私有构造方法
private function __construct() {}
public static function getInstance() {
if (is_null(self::$_instance)) {
self::$_instance = new Singleton();
}
return self::$_instance;
}
// 防止克隆实例
public function __clone(){
die('Clone is not allowed.' . E_USER_ERROR);
}
}
__toString()
当对象被当做字符串是调用此方法。
PHP 5.2.0 之前,__toString() 方法只有在直接使用于 echo 或 print 时才能生效。PHP 5.2.0 之后,则可以在任何字符串环境生效(例如通过 printf(),使用 %s 修饰符),但不能用于非字符串环境(如使用 %d 修饰符)。自 PHP 5.2.0 起,如果将一个未定义 __toString() 方法的对象转换为字符串,会产生 E_RECOVERABLE_ERROR 级别的错误。
// Declare a simple class
class TestClass
{
public function __toString() {
return 'this is a object';
}
}
class Penguin {
public function __construct($name) {
$this->species = 'Penguin';
$this->name = $name;
}
public function __toString() {
return $this->name . " (" . $this->species . ")\n";
}
}
$class = new TestClass();
echo $class;
$tux = new Penguin('tux');
echo $tux;
在 TestClass 的调用中我们输出了一个友好的提示,而在 Penguin 我们将对象的属性组合后输出,比如在模板中调用。
__invoke()
当尝试用函数的方式调用一个对象是触发此方法。
PHP 5.3.0 添加
<?php
class CallableClass
{
function __invoke($x) {
var_dump($x);
}
}
$obj = new CallableClass;
$obj(5); // int(5)
var_dump(is_callable($obj)) // bool(true)
__set_state()
调用 var_export() 导出类时,此魔术方法被调用。
PHP 5.1.0 添加
<?php
class A
{
public $var1;
public $var2;
public static function __set_state ($an_array) {
$obj = new A;
$obj->var1 = $an_array['var1'];
$obj->var2 = $an_array['var2'];
return $obj;
}
}
$a = new A;
$a->var1 = 5;
$a->var2 = 'foo';
var_dump(var_export($a));
__debuginfo()
这个方法在对对象使用 var_dump()
时调用。
PHP 5.6.0 添加
<?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)
}
*/
PHP 的魔术方法及其应用的更多相关文章
- PHP基础知识之魔术方法
__construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sle ...
- 前端学PHP之面向对象系列第二篇——魔术方法
× 目录 [1]构造方法 [2]析构方法 [3]不可访问属性[4]对象复制[5]字符串[6]对象不存在[7]自动加载类[8]串行化[9]函数调用 前面的话 php在面向对象部分有很多相关的魔术方法,这 ...
- PHP中的魔术方法(2)
1.__get.__set这两个方法是为在类和他们的父类中没有声明的属性而设计的__get( $property ) 当调用一个未定义的属性时访问此方法__set( $property, $value ...
- 魔术方法__sleep 和 __wakeup
感觉序列化和反序列化用得倒是比较少了,而json_encode和json_decode用得相对多,都是转化成串,进行入库.传输等.json更方便,但是序列化和反序列化结合这两个魔术方法使用倒还行< ...
- Python魔术方法-Magic Method
介绍 在Python中,所有以"__"双下划线包起来的方法,都统称为"Magic Method",例如类的初始化方法 __init__ ,Python中所有的魔 ...
- php魔术方法使用场景
php魔术方法-----__tostring(),__invoke,__call(),__callStatic ... __tostring(),__invoke() __tostring()方法是在 ...
- PHP中的魔术方法:__construct, __destruct , __call, __callStatic,__get, __set, __isset, __unset , __sleep, __wakeup, __toString, __set_state, __clone and __autoload
1.__get.__set 这两个方法是为在类和他们的父类中没有声明的属性而设计的: __get( $property ) 当调用一个未定义的属性时访问此方法: __set( $property, $ ...
- PHP 类中的魔术方法
定义: PHP类中以两个下画线“__”开头的方法被称为魔术方法. 分类: 例如:构造方法:__construct:析构方法:__destruct:动态重载:__set().__get().__call ...
- php中的魔术方法
__construct 构造器是一个魔术方法,当对象被实例化时它会被调用.在一个类声明时它常常是第一件做的事但是没得必要他也像其他任何方法在类中任何地方都可以声明,构造器也能像其他方法样继承.如果我们 ...
- PHP面向对象之魔术方法复习
魔术方法复习 2014-9-2 10:08:00 NotePad++ By jiancaigege 飞鸿影~========================= 1.__construct() 构造方法 ...
随机推荐
- 选iphone5可以正常编译运行 , 但是5s和6和6s都会编译报错
选iphone5可以正常编译运行 但是5s和6和6s都会编译报错 iphone6编译报错iphone5s编译报错 解决办法是,Build settings里面把Architectures里面的$( ...
- MySQL数据库备份详解
原文:MySQL数据库备份详解 对于任何数据库来说,备份都是非常重要的 数据库复制不能取代备份的作用 比如我们由于误操作,在主数据库上删除了一些数据,由于主从复制的时间很短,在发现时,从数据库上的数据 ...
- 云主机启动Node服务后,关闭控制台,无法访问的问题
之前一直用node app.js操作,开启服务后,关闭控制台,仍然可以正常访问我的网站.但昨晚新买腾讯云的服务器后,发现关闭控制台后,就无法访问网站了.然后给腾讯云发了个工单.腾讯云的工程师给了一篇技 ...
- win10下安装docker步骤(一)
一.启用Hyper-V 打开控制面板 - 程序和功能 - 启用或关闭Windows功能,勾选Hyper-V,然后点击确定即可,如图: 请注意电脑默认的Hyper-V虚拟机监控程序是不能进行勾选的,需要 ...
- 【Codeforces Round #438 A】Bark to Unlock
[链接]h在这里写链接 [题意] 在这里写题意 [题解] 枚举它是在连接处,还是就是整个字符串就好. [错的次数] 0 [反思] 在这了写反思 [代码] #include <bits/stdc+ ...
- C# opcode 查询源码
Add|将两个值相加并将结果推送到计算堆栈上.Add.Ovf|将两个整数相加,执行溢出检查,并且将结果推送到计算堆栈上.Add.Ovf.Un|将两个无符号整数值相加,执行溢出检查,并且将结果推送到计算 ...
- Stompjs websocket vue
公司项目要求要有消息提醒机制 , 多方面考虑用了ActiveMQ ,基本上现在主流的后台语言都没啥问题 , php phthon java nodejs , 等等都没问题 , 各位道友可以去查阅相关资 ...
- 堆(stack) 之 c 和 c++模板实现(空类默认成员函数 初谈引用 内联函数)
//stack 的基本操作 #include <iostream> using namespace std; const int maxn = 3; typedef struct Stac ...
- matlab 高阶(二) —— 数值、溢出问题的解决
gammaln() 在处理上溢和下溢方面要比 log(gamma()) 更好: log1p() (1 plus)对于较小的 x 值时,log1p(x) 要比 log(1+x) 更为精确: 当 x 取值 ...
- [Unity3D]Unity3D圣骑士模仿游戏开发传仙灵达到当局岛
大家好,我是秦培.欢迎关注我的博客.我的博客地址blog.csdn.net/qinyuanpei. 在前面的文章中.我们分别实现了一个自己定义的角色控制器<[Unity3D]Unity3D游戏开 ...