php常用的魔术方法

php规定以两个下划线(__)开头的方法都保留为魔术方法,所以建议大家函数名最好不用__开头,除非是为了重载已有的魔术方法

PHP中的魔术方法有 :__get, __set, __isset, __unset,__construct, __destruct , __call, __callStatic, , __sleep, __wakeup, __toString, __set_state, __clone, __autoload,__invoke
详解:

1.__get,__set

这两个方法是为在类和他们的父类中没有声明的属性而设计的 
__get( $property ) 当调用一个未定义的属性时,此方法会被触发,传递的参数是被访问的属性名 
__set( $property, $value ) 给一个未定义的属性赋值时,此方法会被触发,传递的参数是被设置的属性名和值;这里的没有声明包括当使用对象调用时,访问控制为proteced,private的属性(即没有权限访问的属性)

// 如果类中的属性设置为私有属性,在类的实例中是无法访问的,但怎样才能访问呢?
// 我们就可以使用__get()
Class Person
{
    private $name;
    private $age;


function __get($proName)
{
    return this->$proName;
}
}
// 实例化 
$per=new Person()
$per->$name; //这样是取不到值的
// 但是如果我们在类中增加__GET方法
// 我们再次调用$per->$name 就可以访问了
// 这样做有人会提出疑问了,这样可以直接访问私有变量,和声明成公有的有什么区别呢?
// 如果声明成公有的,我们可以任意读取,如果是私有,如果我们增加了get方法,那么每次调用私有属性都会 
// 调用GET方法的内容,这样我们就可以在get方法中增加一些逻辑处理。
// 原理同上,我们可以再类中添加__set()函数,每当通过调用类实例给私有属性赋值,都会执行__set函数 , 
// 函数原型:
function __set($proName,$value)
{
this->$proName=$value;
}

//既然是方法赋值,我们就可以做一些逻辑处理

2.__isset、__unset 

__isset( $property ) 当在一个未定义的属性上调用isset()函数时调用此方法 (判断类中私有属性或方法是否存在时自动调用)
__unset( $property ) 当在一个未定义的属性上调用unset()函数时调用此方法 (清除类中私有变量时自动调用)
与__get方法和__set方法相同,这里的没有声明包括当使用对象调用时,访问控制为proteced,private的属性(即没有权限访问的属性) 

//isset 方法,该方法用于判定属性和方法是否存在,但是我们无法通过类类实例判断类中的某个私有属性是否 //存在
//如果我们使用isset(per->$name);//返回值是false,但是$name属性的确存在,怎么解决呢?
//解决方法:
//1.将$name定义为私有属性
//2.在类定义中添加

function __isset($proName)
{
Return  isset(this->$proName);//再类内部是可以访问私有属性的
}

// 这样的话我们再次调用isset($name);返回值就为true了
//unset方法可以删除属性,当我们需要删除类中属性的时候,如果是公有属性我们可以直接
删除,但是如果是私有我们只通过该方法就无法实现了
怎样实现呢我们可以使用__unset()方法实现该功能我们需要在类中添加

function __unset($proName)
{
unset(this->$proName);
}

//现在我们再调用unset($name);就可以删除person类中的私有属性$name了

3.__call

__call( $method, $arg_array ) 当调用一个未定义的方法是调用此方法 (当调用类实例中不存在的函数时自动执行),该方法有两个参数,第一个参数 $function_name 会自动接收不存在的方法名,第二个 $arguments 则以数组的方式接收不存在方法的多个参数.这里的未定义的方法包括没有权限访问的方法;如果方法不存在就去父类中找这个方法,如果父类中也不存在就去调用本类的__call()方​法,如果本类中不存在__call()方法就去找父类中的__call()方法;如果试图调用类中不存在的函数,会出现语法错误,为了能够友好的提示
我们可以在类中声明Call()方法;

function __call($funName,$argu)
{
    echo "名为".$funName."参数为".printf($argh)."的函数不存在",
}
<?php
class Person
{                             
    function say()
    {  
                              
           echo "Hello, world!<br>"; 
    }      
        
    /**
     * 声明此方法用来处理调用对象中不存在的方法
     */
    function __call($funName, $arguments)
    { 
          echo "你所调用的函数:" . $funName . "(参数:" ;  // 输出调用不存在的方法名
          print_r($arguments); // 输出调用不存在的方法时的参数列表
          echo ")不存在!<br>\n"; // 结束换行                      
    }                                          
}
$Person = new Person();            
$Person->run("teacher"); // 调用对象中不存在的方法,则自动调用了对象中的__call()方法
$Person->eat("小明", "苹果");             
$Person->say();                        

运行结果:

你所调用的函数:run(参数:Array ( [0] => teacher ) )不存在!

你所调用的函数:eat(参数:Array ( [0] => 小明 [1] => 苹果 ) )不存在!

Hello, world!

4.__clone

对象的复制(引用赋值)
$per1=$per2; 而这在内存中只有一块地址
而$per1=clone $per2   这时有两块内存地址

5.__toString 

用于定义输出对象引用时调用  常用于打印一些对象的信息 必须有返回值(返回一个字符串)

在将一个对象转化成字符串时自动调用,比如使用echo打印对象时
如果类没有实现此方法,则无法通过echo打印对象,否则会显示:Catchable fatal error: Object of class test could not be converted to string in

在PHP 5.2.0之前,__toString方法只有结合使用echo() 或 print()时 才能生效。PHP 5.2.0之后,则可以在任何字符串环境生效(例如通过printf(),使用%s修饰符),但 不能用于非字符串环境(如使用%d修饰符)。从PHP 5.2.0,如果将一个未定义__toString方法的对象 转换为字符串,会报出一个E_RECOVERABLE_ERROR错误。

// eg:有一个persion类
$per =new persion()
echo $per;    //直接调用会出错
//我们可以在类的定义中添加__tostring()方法
function  __Tostring()
{
    $str=this->$name.this->age;
       return $str;
}

6.__autoload 
自动加载使用的类文件  该函数是在引用的页面添加,它会在试图使用尚未被定义的类时自动调用。通过调用此函数,脚本引擎在 PHP 出错失败前有了最后一个机会加载所需的类。 
我们都使用过这样情况,在页面中需要调用其他php文件,我们需要使用include方法
但是如果有几十个页面需要引用,未免太过繁琐,我们可以在该页面中使用autoload方法

function __autoload($className)
{
    include $className.".php";
}
//这样凡是引用到其他类的地方,都会自动引用该类文件  前提类文件的名称必须是   类名.php

如果要定义一个全局的自动加载类,则必须用spl_autoload_register()方法将处理类注册到PHP标准库:

<?php   
class Loader   
{   
    static function autoload_class($class_name)   
{   
//寻找正确的$class_name类,并引入,没有则抛出异常   
}   
}   
/**
*   设置对象的自动载入
*   spl_autoload_register — Register given function as __autoload() implementation
*/   
spl_autoload_register(array('Loader', 'autoload_class'));   
$a = new Test();//Test没用require就实例化,实现自动加载,很多框架就用这种方法自动加载类   
?>

//注意: 在 __autoload 函数中抛出的异常不能被 catch 语句块捕获并导致致命错误,所以应该在函数本身做 //捕获

7.__construct、__destruct 

__construct 构造方法,当一个对象创建时调用此方法,相对于PHP4使用此方法的好处是:可以使构造方法有一个独一无二的名称,无论它所在的类的名称是什么.这样你在改变类的名称时,就不需要改变构造方法的名称 

<?php
    class Person
    {                                                                      
            public $name;        
            public $age;        
            public $sex;        
                                                                 
        /**
         * 显示声明一个构造方法且带参数
         */                                                                                       
        public function __construct($name="", $sex="男", $age=22)
        {      
            $this->name = $name;
            $this->sex = $sex;
            $this->age = $age;
        }
        
        /**
         * say 方法
         */
        public function say()
        { 
            echo "我叫:" . $this->name . ",性别:" . $this->sex . ",年龄:" . $this->age;
        }   
                                                                                           
    }

$Person1 = new Person();
echo $Person1->say(); //输出:我叫:,性别:男,年龄:22

$Person2 = new Person("小明");
echo $Person2->say(); //输出:我叫:小明,性别:男,年龄:22

$Person3 = new Person("李四","男",25);
echo $Person3->say(); //输出:我叫:李四,性别:男,年龄:25

__destruct 析构方法,PHP将在对象被销毁前(即从内存中清除前)调用这个方法。析构方法允许在销毁一个类之前执行的一些操作或完成一些功能,比如说关闭文件、释放结果集等。析构方法是PHP5才引进的新内容。默认情况下,PHP仅仅释放对象属性所占用的内存并销毁对象相关的资源,析构函数允许你在使用一个对象之后执行任意代码来清除内存。当PHP决定你的脚本不再与对象相关时,析构函数将被调用。 在一个函数的命名空间内,这会发生在函数return的时候。 对于全局变量,这发生于脚本结束的时候。 如果你想明确地销毁一个对象,你可以给指向该对象的变量分配任何其它值.通常将变量赋值勤为NULL或者调用unset. 

//析构方法的声明格式
//注意:析构函数不能带有任何参数
//一般来说,析构方法在PHP中并不是很常用,它属类中可选择的一部分,通常用来完成一些在对象销毁前的清理 
//任务。
function __destruct()
{
 //方法体
}
<?php
class Person{     
                                                        
    public $name;         
    public $age;         
    public $sex;         
                                                                    
    public function __construct($name="", $sex="男", $age=22)
    {   
        $this->name = $name;
        $this->sex  = $sex;
        $this->age  = $age;
    }
    
    /**
     * say 说话方法
     */
    public function say()
    {  
        echo "我叫:".$this->name.",性别:".$this->sex.",年龄:".$this->age;
    }    
    
    /**
     * 声明一个析构方法
     */
    public function __destruct()
    {
            echo "我觉得我还可以再抢救一下,我的名字叫".$this->name;
    }
}

$Person = new Person("小明");
unset($Person); //销毁上面创建的对象$Person

//上面的程序运行时输出:我觉得我还可以再抢救一下,我的名字叫小明

8.__sleep,__wakeup

serialize() 检查类中是否有魔术名称 __sleep 的函数。如果这样,该函数将在任何序列化之前运行。它可以清除对象并应该返回一个包含有该对象中应被序列化的所有变量名的数组。 
使用 __sleep 的目的是关闭对象可能具有的任何数据库连接,提交等待中的数据或进行类似的清除任务。此外,如果有非常大的对象而并不需要完全储存下来时此函数也很有用。 
相反地,unserialize() 检查具有魔术名称 __wakeup 的函数的存在。如果存在,此函数可以重建对象可能具有的任何资源。 
使用 __wakeup 的目的是重建在序列化中可能丢失的任何数据库连接以及处理其它重新初始化的任务

9.__invoke 

当尝试以调用函数的方式调用一个对象时,__invoke 方法会被自动调用

10.__set_state

静态方法,当调用var_export()的时候,才会调用这个静态方法,php5.1.0之后生效。唯一参数是接收一个数组

11.__callStatic 

它的工作方式类似于 __call() 魔术方法,__callStatic() 是为了处理静态方法调用, 
PHP5.3.0以上版本有效 
PHP 确实加强了对 __callStatic() 方法的定义;它必须是公共的,并且必须被声明为静态的。同样,__call() 魔术方法必须被定义为公共的,所有其他魔术方法都必须如此 

// 魔术方法:
// 构造方法:__construct  当实例化一个对象时,自动执行此方法,通常用于赋值操作
// 析构方法:__destruct   释放资源  
// isset魔术方法:__isset  当类外检测一个私有属性时,自动调用魔术方法__isset  [名]
// unset魔术方法:__unset  当类外删除一个私有属性时,自动调用魔术方法__unset  [名]
// get魔术方法: __get     当类外获取一个私有属性时,自动调用魔术方法__get    [名] 
// set魔术方法: __set     当类外设置一个私有属性时,自动调用魔术方法__set    [名,值]
// sleep魔术方法: 当类外使用序列化时调用此方法   serialize(value)
// wakeup魔术方法: 当类外使用反序列化时调用此方法  unserialize(value)
// toString魔术方法:  当直接输入对象时调用此方法,如果不写toString方法,会报一个致命错误,底下代码不执行 ,如果写一个Tostring方法,底下继续执行
// call魔术方法: 当调用一个不存在的方法时自动调用
// 自动加载:  __autoload   引入文件,注意:引入文件的一个规律    spl_autoload_register("方法名")
// 克隆方法:  __clone  克隆一个方法
//实例化对象时,会调用对象的__construct方法
$obj = new Object();
//给对象不存在的属性赋值时,会调用对象的__set方法
$obj->title = "hello";
//使用对象不存在的属性时,会调用对象的__get方法
echo $obj->title;
//调用对象不存在的方法时,会调用对象的__call方法
$obj->test("hello",123,567);
//调用不存在的类静态方法时,会调用类的__callStatic方法
Object::staticMethod("static","not found method");
//直接输出对象时,会调用对象的__toString方法
echo $obj;
//将一个对象当作函数一样使用时,会调用对象的__invoke方法
echo $obj("test");
//克隆对象时,会调用对象的__clone方法
$obj2 = clone $obj;
//判断对象属性是否存在时,会调用对象的__isset方法
var_dump(isset($obj->aaa));
//销毁对象属性时,会调用对象的__unset方法
unset($obj->aaa);
 
class Object{
 
  protected $array = array();
 
  function __construct()
  {
    echo __METHOD__."你正在实例化对象<br>";
  }
 
  function __set($name, $value)
  {
    $this->array[$name]=$value;
  }
 
  function __get($name)
  {
    return $this->array[$name];
  }
 
  function __call($name, $arguments)
  {
    var_dump($name,$arguments);
    return "magic function\n";
  }
 
  static function __callStatic($name, $arguments)
  {
    var_dump($name,$arguments);
    return "magic static function";
  }
 
  function __toString()
  {
    return __CLASS__.'<br>';
  }
 
  function __invoke($arguments)
  {
    var_dump($arguments);
    return __METHOD__.'<br>';
  }
 
  function __clone()
  {
    echo __METHOD__."你正在克隆对象<br>";
  }
 
  function __isset($name)
  {
    echo __METHOD__."你想判断有没有属性".$name."<br>";
    return 1;
  }
 
  function __unset($name)
  {
    echo __METHOD__."你想删除属性".$name."<br>";
  }
 
  function __destruct()
  {
    echo __METHOD__."你正在注销对象<br>";
  }
}

  • 3
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值