魔术方法

Posted 一阙梅曲香素笺

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了魔术方法相关的知识,希望对你有一定的参考价值。

 

特征,系统自定义的函数方法,都以__开头,自动被调用,可被继承,不可以自己定义,不能被static修饰除了__callStatic()

__construct() __destruct() __call() __callStatic() __get() __set() __isset() __unset() __sleep() __wakeup() __toString() __invoke() __set_state() __clone()  __debugInfo() 等方法在 php 中被称为"魔术方法"Magic methods)。在命名自己的类方法时不能使用这些方法名,除非是想使用其魔术功能。

PHP 将所有以 __(两个下划线)开头的类方法保留为魔术方法。所以在定义类方法时,除了上述魔术方法,建议不要以 __ 为前缀。

__toString() 

public string __toString ( void )

__toString() 方法用于一个类被当成字符串时应怎样回应。例如 echo $obj; 应该显示些什么。此方法必须返回一个字符串,否则将发出一条 E_RECOVERABLE_ERROR 级别的致命错误。

 

示例1

<?php
// Declare a simple class
class  TestClass
{
    public  $foo ;

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

    public function  __toString () {
        return  $this -> foo ;
    }
}

$class  = new  TestClass ( \'Hello\' );
echo  $class ;
?> 

以上例程会输出:

Hello

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

方法重载

public mixed __call ( string $name , array $arguments )

public static mixed __callStatic ( string $name , array $arguments )

在对象中调用一个不可访问方法时,__call() 会被调用。

用静态方式中调用一个不可访问方法时,__callStatic() 会被调用。

$name 参数是要调用的方法名称。 $arguments 参数是一个枚举数组,包含着要传递给方法 $name 的参数。

__call()__callStatic()用法一样,只是__callStatic()的方法为静态方法

 

属性重载

 

public void __set ( string $name , mixed $value )

 

public mixed __get ( string $name )

 

public bool __isset ( string $name )

 

public void __unset ( string $name )

 

在给不可访问属性赋值时,__set() 会被调用。

 

读取不可访问属性的值时,__get() 会被调用。

 

当对不可访问属性调用 isset()  empty() 时,__isset() 会被调用。

 

当对不可访问属性调用 unset() 时,__unset() 会被调用。

 

参数 $name 是指要操作的变量名称。__set() 方法的 $value 参数指定了 $name 变量的值。

 

属性重载只能在对象中进行。在静态方法中,这些魔术方法将不会被调用。所以这些魔术方法都不能被 声明为 static。从 PHP 5.3.0 , 将这些魔术方法定义为 static 会产生一个警告。

 

Note:

 

因为 PHP 处理赋值运算的方式,__set() 的返回值将被忽略。类似的, 在下面这样的链式赋值中,__get() 不会被调用: 

 

$a = $obj->b = 8;

 

Note:

 

在除 isset() 外的其它语言结构中无法使用重载的属性,这意味着当对一个重载的属性使用 empty() 时,重载魔术方法将不会被调用。

 

为避开此限制,必须将重载属性赋值到本地变量再使用 empty() 

 

复制

 

在多数情况下,我们并不需要完全复制一个对象来获得其中属性。但有一个情况下确实需要:如果你有一个 GTK 窗口对象,该对象持有窗口相关的资源。你可能会想复制一个新的窗口,保持所有属性与原来的窗口相同,但必须是一个新的对象(因为如果不是新的对象,那么一个窗口中的改变就会影响到另一个窗口)。还有一种情况:如果对象 A 中保存着对象 B 的引用,当你复制对象 A 时,你想其中使用的对象不再是对象 B 而是 B 的一个副本,那么你必须得到对象 A 的一个副本。

 

对象复制可以通过 clone 关键字来完成(如果可能,这将调用对象的 __clone() 方法)。对象中的 __clone() 方法不能被直接调用。

 

$copy_of_object = clone $object;

 

当对象被复制后,PHP 5 会对对象的所有属性执行一个浅复制(shallow copy)。所有的引用属性 仍然会是一个指向原来的变量的引用。

 

void __clone ( void )

 

当复制完成时,如果定义了 __clone() 方法,则新创建的对象(复制生成的对象)中的 __clone() 方法会被调用,可用于修改属性的值(如果有必要的话)。

 

class City{

    protected $name;
    private $area;

    function __construct($name, $area){
        $this->name = $name;
        $this->area = $area;
    }

    /**
     * __get魔术方法,它是在外部访问该类中不能直接访问的属性时自动被调用
     * 魔术方法都有其默认的定义格式,不能随意的更改
     * 魔术方法不能被添加static静态的修饰符
     * __get魔术方法必须有一个返回值
     * @param $name     它对应的是类中的被声明的属性的名称,格式为字符串
     */
    function __get($name){
//        echo \'我被调用了:\'.$name;
        if(isset($this->$name)){
            return $this->$name;
        }else{
            return null;
        }
    }

    /**
     * __set魔术方法,在给类中无法直接访问的属性赋值时自动调用
     * @param $name      被赋值的类中的属性名称,字符串格式
     * @param $value     被赋予的值
     */
    function __set($name, $value){
//        echo \'我被调用了:\'.$name.\'===\'.$value;
        /*
         * property_exists  检测类或者对象中是否包含指定名称的属性
         */
        if(property_exists($this, $name)){
            $this->$name = $value;
        }else{
            echo \'类中没有对应的属性:\'.$name.\'<br>\';
        }
    }

    function __isset($name){
        if(property_exists($this, $name)){
            return isset($this->$name);
        }
    }
    function __unset($name){
//        echo \'需要销毁的属性:\'.$name;
        if(property_exists($this, $name)){
            $this->$name = null;
        }else{
            unset($this->$name);
        }
    }


    /**
     * __toString魔术方法,当使用字符串的方式来输出类的对象时被自动调用
     * 它要求必须返回一个字符串结果
     */
    function __toString(){

        return \'<br>城市名称:\'.$this->name.\',面积:\'.$this->area;
    }

    /**
     * __clone魔术方法,当类的对象被克隆时自动被调用
     * 默认的克隆时浅克隆模式
     * 该方法可以实现克隆时修改某些属性的值
     */
    function __clone(){
        echo \'<br>调用了clone的魔术方法<br>\';
        $this->area = \'3333平方公里\';
    }

}



$city = new City(\'成都\', \'3000平方公里\');
//__clone()
//$city2 = clone $city;
//var_dump($city);
//echo \'<br>\';
//var_dump($city2);
//echo \'<br>\';

//__toString()
//var_dump($city);
//echo \'<br>\';
//print_r($city);
//echo \'<br>\';
//print $city;
//echo $city;

//__call()
//$city->test();
//$city->test1(\'哈哈哈哈\');
//$city->test2(100,200);

// get()
//echo \'名称:\'.$city->name.\'<br>\';
//echo \'面积:\'.$city->area.\'<br>\';
//echo \'人口:\'.$city->people.\'<br>\';
//echo \'<br>\';
//set()
//$city->name = \'重庆\';
////$city->people = \'15000000\';

//unset()
//unset($city->name);
//echo \'名称:\'.$city->name.\'<br>\';
//echo \'面积:\'.$city->area.\'<br>\';
//echo \'人口:\'.$city->people.\'<br>\';
//echo \'<br>\';
//var_dump($city);

//根据$test是否有值使用isset
//$test = false;
//if(isset($test)){ echo \'OK\';}

//判断是否有people这个变量
//if(isset($city->people)){
//    echo \'====有值====\';
//}else{
//    echo \'====没有获取到值====\';
//}

 

 

 

 

 

以上是关于魔术方法的主要内容,如果未能解决你的问题,请参考以下文章

PHP中的常见魔术方法功能作用及用法实例

object基础魔术方法使用代码

object基础魔术方法使用代码

python魔术方法

Python 魔术方法笔记

D15内置函数和魔术方法