PHP7魔术方法在实际编程中的应用

1、读取php对象的不可访问属性(private/protected)

class Person{
    private $name;
    private $age ;
    public function __construct($name,$age)
    {
        $this->name = $name;
        $this->age = $age;
    }
}

$person = new Person('gofor',28);
echo $person->name;//直接报错
echo $person->age;//直接报错

上面代码运行将发生致命错误,Cannot access private property Person::$name

那如何访问类的私有或保护属性呢?

方法1:为每个private/protected属性定义公有方法

class Person{
    private $name;
    private $age ;
    public function __construct($name,$age)
    {
        $this->name = $name;
        $this->age = $age;
    }
    public function getName(){
        return $this->name;
    }
    public function getAge(){
        return $this->age;
    }
}
$person = new Person('gofor',28);
echo $person->getName();
echo $person->getAge();

这时候代码正常运行
这种方法需要为每个private/protected属性定义对应getXXX方法,代码量比较大,且新增private/protected属性需要新增对应的方法

方法2:使用__get魔术方法

读取不可访问(private/protected)的属性值时自动调用__get方法
代码实现

class Person{
    private $name;
    private $age ;
    public function __construct($name,$age)
    {
        $this->name = $name;
        $this->age = $age;
    }

    //$name为类的属性名
    public function __get($name)
    {
        //存在类属性
       if(isset($this->$name)) {
           return $this->$name;
       }
        return '属性'.$name.'不存在';
    }

}
$person = new Person('gofor',28);
echo $person->name;//输出gofor
echo $person->age;//输出28

这样调用类私有(或保护)属性,通过__get一个魔术方法就搞定,比方法1更简单方便。

2、给访问受限属性(private/protected)赋值

同样,$person->name = 'Tom';给访问受限属性这样赋值会报错。
那如何给访问受限属性赋值呢?
同理,方法1:为每个访问受限属性添加对应的setXXX()共有方法
方法2:使用__set魔术方法
__set( $property, $value )    给一个访问受限(private/protected)属性赋值时调用
代码实现如下:

class Person{
    protected $name;
    private $age ;
    public function __construct($name,$age)
    {
        $this->name = $name;
        $this->age = $age;
    }
    //$name为类的属性名
    public function __get($name)
    {
        //存在类属性
        if(isset($this->$name)) {
            return $this->$name;
        }
        return '属性'.$name.'不存在';
    }
    //$name为类的属性名,$value为设置的值
    public function __set($name, $value)
    {
        $this->$name = $value;
    }
}

$person = new Person('gofor',28);
$person->name = 'Tom';
$person->age = 29;
echo $person->name;//输出Tom
echo $person->age;//输出29

3、魔术方法__construct

__construct 构造方法,当一个对象被创建时调用此方法,可以给类初始化数据,如属性赋值
代码如下:

class Person
{
    protected $name;
    private $age;
//当一个对象被创建时调用此方法
//即$person = new Person('gofor',28)调用____construct
    public function __construct($name, $age)
    {
      //类初始化数据
        $this->name = $name;
        $this->age = $age;
    }
}

4、魔术方法__call

如何防止调用类不存在的方法而报错呢?
使用__call魔术方法
__call( $method, $arg_array ) 当调用一个未定义(包括没有权限访问)的方法是调用此方法。其中$method是调用的方法名, $arg_array是参数数组,传给方法的参数。
代码如下

class Person{
    protected $name;
    private $age ;
    public function __construct($name,$age)
    {
        $this->name = $name;
        $this->age = $age;
    }
}
$person = new Person('gofor',28);
$person->say(‘hello’);//Person类未定义say方法,这时程序会报错

如何防止调用类不存在的方法而报错呢?使用__call魔术方法可以实现。代码如下:

class Person{
    protected $name;
    private $age ;
    public function __construct($name,$age)
    {
        $this->name = $name;
        $this->age = $age;
    }
    public function __call($name, $arguments)
    {
        echo '方法:'.$name.'不存在';
        dump($arguments);
    }
}
$person = new Person('gofor',28);
$person->say(‘hello’);//Person类未定义say方法,这时会调用__call正常访问

上述代码运行结果为:

方法:say不存在
array (size=1)
  0 => string 'hello' (length=5)

魔术方法__call其中一个比较熟悉的应用场景就是web开发的MVC模式中,假设控制器调用了一个不存在的方法,那么只要定义了__call魔术方法就可以友好处理这种情况。

5、魔术方法__callStatic

当调用类一个不存在的静态方法(就是带有static关键字的方法)会调用__callStatic的魔术方法
它的工作方式类似于 __call() 魔术方法,不做详细描述。

6、魔术方法__toString

__toString方法在将一个对象转化成字符串时自动调用,比如使用echo打印对象时,如果类没有实现此方法,则无法通过echo打印对象

$person = new Person('gofor',28);
echo $person;

在没有给Person定义__toString时,会报错# Object of class Person could not be converted to string
实现__toString方法之后,就可以按照我们设定的格式打印$person信息了
代码如下:

class Person{
    protected $name;
    private $age ;
    public function __construct($name,$age)
    {
        $this->name = $name;
        $this->age = $age;
    }
    public function __toString()
    {
       return 'name:'.$this->name.',age:'.$this->age;
    }
}

$person = new Person('gofor',28);
echo $person;

运行结果如下:

name:gofor,age:28

7、魔术方法__clone

克隆对象时被调用,如下代码:

$person = new Person('gofor',28);//创建对象
$person2=clone $person;//这里克隆对象,会调用__clone魔术方法

完整代码如下:

class Person{
    protected $name;
    private $age ;
    public function __construct($name,$age)
    {
        $this->name = $name;
        $this->age = $age;
    }
    public function __toString()
    {
       return 'name:'.$this->name.',age:'.$this->age;
    }


    public function __call($name, $arguments)
    {
        echo '方法:'.$name.'不存在';
        dump($arguments);
    }

    //$name为类的属性名
    public function __get($name)
    {
        //存在类属性
        if(isset($this->$name)) {
            return $this->$name;
        }
        return '属性'.$name.'不存在';
    }
    //$name为类的属性名,$value为设置的值
    public function __set($name, $value)
    {
        $this->$name = $value;
    }

    public function __clone()
    {
        echo '我被复制了';
    }
}
$person = new Person('gofor',28);
$person2 = clone $person;//此处会调用__clone方法

运行上述代码结果如下:

我被复制了

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李维山

帮到你就行 不差钱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值