三、魔术方法

魔术方法其实是 PHP 为开发者提供了一种规避因为对类的私有属性操作,对不存在的方法调用等类似原因而导致的错误.下面就对 PHP 的魔术方法做简单介绍.

  • __set
  • __get
  • __isset
  • __unset
  • __call
  • __callStatic
  • __invoke

1. __set()__get() 魔术方法

作用: 对类的私有属性赋值或读取而不产生错误的方法.

之前我们说过, private 修饰的类的属性是私有的,不能被外部赋值也不能被取值, 但 PHP 也提供了一套魔术方法 __set()__get(), 如果在类中定义了 __set() 方法,当为私有属性赋值时,就会调用此方法, 类似的 __get() 方法,当有私有属性被读取时,就会调用此方法.

另外,值得注意的是,这两个魔术方法可以为类的实例动态设置新的属性值,不过不是很推荐这样使用,没有在类中定义的属性业务中被创建并使用会导致代码难以维护.

class Vehicle
{
    private $creator = '未知';

    // __set() 魔术方法
    public function __set($name, $value)
    {
        $this->$name = $value;
    }

    // __get() 魔术方法
    public function __get($name)
    {
        return $this->$name;
    }
}

$vehicle = new Vehicle();
// 为私有属性赋值
$vehicle->creator = 'zZ爱吃菜';
// 读取私有属性
var_dump($vehicle->creator);
// 动态绑定新属性并赋值
$vehicle->creator2 = 'zZ爱吃菜2';
// 读取新属性
var_dump($vehicle->creator2);
// 输出结果:
string(11) "zZ爱吃菜" 
string(12) "zZ爱吃菜2"

2. __isset() 方法

作用: 判断类的私有属性是否存在,而不产生错误

在 PHP 类中定义的私有属性, 通过 isset 是不能进行判断是否的, 如果在类中定义了 __isset() 方法,当为私有属性赋值时,就会调用此方法

class Vehicle
{
    private $creator = '未知';
}

$vehicle = new Vehicle();
var_dump(isset($vehicle->creator));
// 输出结果: bool(false)

如果定义了 __isset() 魔术方法,结果如下:

class Vehicle
{
    private $creator = '未知';

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

$vehicle = new Vehicle();
var_dump(isset($vehicle->creator));
// 输出结果: bool(true)

3. __unset() 方法

作用: 对类的私有属性进行销毁操作(unset), 而不产生错误

同理, 当删除一个类的私有属性是,如果定义了 __unset() 方法,就会调用此方法.

我们知道,私有属性是不能够被 unset 的. 代码如下:

class Vehicle
{
    private $creator = '未知';
}

$vehicle = new Vehicle();
unset($vehicle->creator);
// 输出结果:
PHP Fatal error:  Uncaught Error: Cannot access private property Vehicle::$creator

但是,当我们定义了 __unset() 魔术方法时,就可以对私有属性进行 unset 了

class Vehicle
{
    private $creator = '未知';
    public function __unset($name)
    {
        echo '删除 creator 私有属性';
        unset($this->creator);
    }
}

$vehicle = new Vehicle();
unset($vehicle->creator);
// 输出结果:
删除 creator 私有属性

4. __call() 魔术方法

作用: 避免调用类的方法不存在, 而尝试错误.

当调用的类的方法不存在时, 如果类定义了 __call() 魔术方法,就会调用此方法.

如果我们调用一个类不存在的方法会有如下错误:

class Vehicle
{}
$vehicle = new Vehicle();
$vehicle->run(100, 'guangzhou');
// 输出结果:
PHP Fatal error:  Uncaught Error: Call to undefined method Vehicle::run()

如果我们定义了 __call

class Vehicle
{
    public function __call($name, $arguments)
    {
        var_dump($name, $arguments);
    }
}

$vehicle = new Vehicle();
$vehicle->run(100, 'guangzhou');
// 输出结果: 会在这里打印调用的方法名,以及属性
string(3) "run"
array(2) {
  [0]=>
  int(100)
  [1]=>
  string(9) "guangzhou"
}

5. __callStatic 方法

作用: 避免调用类的静态方法不存在, 而尝试错误.

__call 类似,只不过针对的是 类 的静态方法, 另外 __callStatic 也必须是静态方法 代码如下:

class Vehicle
{
    public static function __callStatic($name, $arguments)
    {
        var_dump($name, $arguments);
    }
}
// 调用不存在的静态方法
Vehicle::run(100, 'guangzhou');
// 输出结果: 
string(3) "run"
array(2) {
  [0]=>
  int(100)
  [1]=>
  string(9) "guangzhou"
}

6. __invoke 方法

作用: 避免将类的实例当做函数调用而产生错误

代码如下:

class Vehicle
{
    public function __invoke($arguments)
    {
        var_dump($arguments);
    }
}
$vehicle = new Vehicle();
$vehicle('我不是函数');
// 输出结果:
string(15) "我不是函数"

7. __toString 方法

作用: 避免将类的实例作为字符串打印时发生错误

比较简单,我们直接看代码:

class Vehicle
{
    public function __toString()
    {
        return '我是 Vehicle 字符串打印结果';
    }
}

$vehicle = new Vehicle();
echo $vehicle;

__toString 魔术方法是比较常用的, 比如我们需要对一类字符串便描述时,可调用此方法进行返回描述.

Last Updated: 8/8/2019, 4:10:24 PM