PHP 常用魔术方法总结

__set当给不可访问或不存在属性赋值时被调用

<?php
namespace App;

class Person
{
    public function __set($propertyName, $value)
    {
        $this->propertyName = $value;
    }
}

:

$person = new \App\Person();
$person->name = 'zhangSan';
因为没有name这个属性,此时__set将会触发,没有__set()这个魔术方法就会报错.

使用场景:可以用于一些字段赋值时做验证,当然更建议使用setXX()来实现.

__get读取不可访问或不存在属性时被调用

<?php
namespace App;

class Person
{
    public function __get($propertyName)
    {	
    	return isset($this->$propertyName) ? $this->$propertyName : null;
    }
}

:

$person = new \App\Person();
dd($person->name);  //null;
此时并没有name这个属性,所以会进入__get这个方法中,三目运算符最终结果为null

__isset对不可访问或不存在的属性调用isset()或empty()时被调用

<?php
namespace App;

class Person
{
	private $name = 'ZhangSan';
}

例:
此时$name 是一个私有属性
我们在外部使用 isset($person->$name) 会得到一个fasle结果,如果我们希望在外部使用isset得到对象私有属性的测量,我们就可以使用__isset()这个方法

改善后的代码:

<?php
namespace App;

class Person
{
	protected $name = 'ZhangSan';

	public function __isset($propertyName)
	{
		return isset($this->$propertyName);
	}
}

此时在外部再进行调用isset($person->$name) 就能正常得到私有属性的测量结果.

__unset对不可访问或不存在的属性进行unset时被调用

此时我们需要销毁掉$name属性,正常的操作步骤,我们可能是这样:

unset($person->name);

然后发现我们并无法成功销毁掉$name,因为我们无法销毁掉私有变量.

如果我们想要内部变量可以被销毁,我们需要重载__unset()来实现.
改善后的代码:

<?php
namespace App;

class Person
{
	protected $name = 'ZhangSan';

	public function __unset($propertyName)
	{
		unset($this->$propertyName);
		echo '删除成功';
	}
}

__call调用不可访问或不存在的方法时被调用

<?php
namespace App;

class Person
{
	protected $idCard = '430XXXXXXXXXXXXXXXXX';

	private function getIdCard()
	{
		return $this->$idCard;
	}
}

$person->getIdCard()    //会抛出一个异常 用于提示我们无法调用一个私有方法.
假设我们需要让他提示的更加一点友好一些或者返回一个默认值,就需要重载__call()来实现.

改善后如下:

<?php
namespace App;

class Person
{
	protected $idCard = '430XXXXXXXXXXXXXXXXX';

	private function getIdCard()
	{
		return $this->$idCard;
	}

	public function __call($methodName,$arguments)
	{
		$this->makeException($methodName.' 方法 不存在');
	}

	public function makeException($message)
	{
		throw new \Exception($message);
	}
}

__callStatic调用不可访问或不存在的静态方法时被调用

<?php
namespace App;

class Person
{
	public static  $name = 'ZhangSan';

	public static function getName()
	{
		return self::$name;
	}

	public function __callStatic($method,$arguments)
	{
		return null;
	}
}


例:
\App\Person::getName(); //ZhangSan
\App\Person::getAge();  //null
我们的person类中并没有存在getAge这一的静态方法所以会调用__callStatic方法,在我们laravel框架中就采用了大量的魔术方法。

__clone进行对象clone时被调用,用来调整对象的克隆行为

<?php
namespace App;

class Person
{
	public $instance = 0;

	public function __construct()
	{
		++$this->instance;
	}

	public function __clone()
	{
		++$this->instance;
	}
}

例:
$person = new \App\Person();
$person->instance;   // 1
$person2  = clone $person;
$person->instance;   // 2
在我们的person对象被克隆时,会调用__clone方法,我们可以在这个函数中调整我们的克隆行为.

__toString 当一个类被转换成字符串时被调用

<?php
namespace App;

class Person
{
    public $name = 'ZhangSan';

    public $age = '21';

    public function __toString()
    {
        return 'name:' . $this->name . ',age:' . $this->age;
    }
}

:
$person = new \App\Person();
echo $person;   //name:ZhangSan,age:21
重载__toString()方法后,我们可以将对象向字符串一样输出,但是此方法必须返回一个字符串,否则将发出一条 E_RECOVERABLE_ERROR 级别的致命错误。

__invoke当对象被当做函数使用时,触发.

<?php
namespace App;

class Person
{
    public $name = 'ZhangSan';

    public function getName()
    {
        echo  $this->name;
    }

    public function __invoke($method)
    {
    	if(method_exists($this,$method)){
    		call_user_func([$this,$method]);
    	}
    }
}

:
$person = new \App\Person();

$person('getName'); //打印ZhangSan

__set_state 当调用var_export()导出类时,此静态方法被调用。用__set_state的返回值做为var_export的返回值。

<?php
namespace App;

class Person
{
    public $name = 'ZhangSan';

    public $age = 0;

    public static function __set_state($arr)
    {
    	$obj = new Person;
        $obj->name = $arr['name'];
        $obj->age = 1;
        return $obj;
    }
}

$person = new \App\Person();
eval('$obj = ' . var_export($person, true) . ';'); 
var_dump($obj);

当调用var_dump()打印对象时被调用

<?php
namespace App;

class Person
{
    public $name = 'ZhangSan';

    public $age = 0;

    public function __debuginfo()
    {
    	return [
    		'name'	=> null,
    		'age'	=> $this->age,
    	];
    }
}

:
$person = new \App\Person();
var_dump($person);
//object(App\Person)#285 (2) { ["name"]=> NULL ["age"]=> int(0) }

我们可以debuginfo方法中来自定义被打印的属性

以上就总结了一些常用的魔术方法用途,实际在我们的laravel框架中也采用了大量的魔术方法,合理的运用魔术方法可以让我们完成一些很酷的操作就像变魔术一样.

日记本

如果觉得我的文章对您有用,请随意赞赏。您的支持将鼓励我继续创作!

赞赏支持
被以下专题收入,发现更多相似内容