php的魔术方法

x33g5p2x  于2022-03-06 转载在 其他  
字(5.2k)|赞(0)|评价(0)|浏览(506)

前言

Php可以说是一个面向对象的语言,php的类中有自己独有的一些方法,不同于别的编程语言,php在定义类中除了我们自己定义的属性方法以外,Php还有一写魔术方法,当我们把这些方法写出来后,我们并不需要自己去调用。系统就会在触发某些条件之后自动调用。

注意,当我们没有写这些魔术方法时,系统不会去调用这些魔术方法。

php提供的魔术方法有很多,这里我们只介绍常用的几个。

  1. __get读取不可访问或不存在的属性的值时,__get() 会被调用。
  2. __set在给不可访问或不存在的属性赋值时,__set() 会被调用。
  3. __isset() 当对不可访问或不存在属性调用 isset() 或 empty() 时,__isset() 会被调用。
  4. __unset();当对不可访问或不存在的属性调用 unset() 时,__unset() 会被调用。
  5. __call()在对象中调用一个不可访问或不存在的方法时,__call() 会被调用。
  6. __clone()可以防止别人克隆我们的对象。
  7. __tostring();方法用于一个类被当成字符串时应怎样回应。例如 echo $obj; 应该显示些什么。
  8. __construct();PHP 5 允行开发者在一个类中定义一个方法作为构造函数。具有构造函数的类会在每次创建新对象时先调用此方法。
  9. __destruct();PHP 5 引入了析构函数的概念,析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行。

你会发现这些魔术方法的前面都有两个下划线__这是因为PHP 将所有以\ __(两个下划线)开头的类方法保留为魔术方法。所以在定义类方法时,除了上述魔术方法,建议不要以\ __ 为前缀。

下面我们单个的介绍每个魔术方法是怎么使用的。

魔术方法

__get()和__set()

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

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

在类中当属性的修饰符是protected和private的时候,在类的外部不能通过对象名的形式进行访问,如果强行读取不可访问的属性,并且你在类的内部写了__get函数,这时候系统就会自动的调用__get魔术方法,当你强行修改不可访问属性值得时候,__set魔术方法就会被执行。

示例:

<?php
class Cat{
    protected $name;
    protected $age;
    protected $sex;

    public function __construct($name,$age,$sex){
        $this -> name = $name;
        $this -> age = $age;
        $this -> sex = $sex;
    }
    //__set方法,可以处理你自己的逻辑
    public function __set($name,$value){
        echo 'set方法被执行了<br>';
        //这里使用这个函数判断当前类中有没有这个属性,防止属性出现null的情况。
        if(property_exists($this, $name)){
            $this -> $name = $value;
        }else{
            echo '你要设置的属性不存在';
        }
    }
    //__get方法,可以处理你自己的逻辑
    public function __get($name){
        echo 'get方法被执行了<br>';
        if(isset($this->$name)){
            return $this -> $name;
        }else{
            echo '你要的属性不存在,或者属性值为空';
        }
    }
}
$cat = new Cat('小花',2,'雌');
echo $cat -> name . '<br>'; //读取不可访问的属性值得时候,get方法被执行
$cat -> age = 5; //修改不可访问的属性值set方法被执行
echo $cat -> age;

property_exists()函数:检查对象或类是否具有该属性

__isset()和__unset()

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

__unset():当对不可访问或不存在的属性调用 unset() 时,__unset() 会被调用。

在类的外部对对象的不能访问属性使用isset函数或empty函数的时候或者这个属性在类中都没有定义。魔术方法__isset()就会执行,而进行unset操作是__unset就会自动调用。

示例:

<?php
class Cat{
    protected $name;
    protected $age;
    protected $sex;

    public function __construct($name,$age,$sex){
        $this -> name = $name;
        $this -> age = $age;
        $this -> sex = $sex;
    }
    //__isset方法,在类中可以对类的属性进行判断,并返回。
    public function __isset($name){
        echo 'isset方法执行了<br>';
        return isset($this -> $name);
    }
    //__unset方法
    public function __unset($name){
        echo 'unset方法执行了<br>';
        if(property_exists($this,$name)){
            unset($this -> $name);
        }else{
            echo '你要销毁的属性不存在';
        }
    }
}
$cat = new Cat('小花',2,'雌');
echo isset($cat -> name);
unset($cat->age);
echo '<pre>';
var_dump($cat);

__call()

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

因为php语言不支持函数的重载,可以使用这个魔术方法进行重载。

示例:

<?php

class Math{

    private function add($a,$b){
        return $a + $b;
    }
    private function add1($a,$b,$c){
        return $a + $b + $c;
    }

    //这个魔术方法中有两个参数,第一个参数是传过来的函数名,第二个参数是传过来的方法中的参数组成的数组。
    public function __call($method,$arr_value){
        if($method == 'add'){
            //得到数组的数量,确定使用那个方法。
            $total = count($arr_value);
            if($total == 2){
                return $this -> add($arr_value[0],$arr_value[1]);
            }else if($total == 3){
                return $this -> add1($arr_value[0],$arr_value[1],$arr_value[2]);
            }
        }
    }

}

$math = new Math();

echo $math -> add(1,2) . '<br>';//私有的方法,没有权限,会调用call方法.
echo $math -> add(1,2,3);

在php中同一类中一定不能有方法名相同的函数。不然后报错。

__clone()

__clone():可以防止别人克隆我们的对象。

php语言中有一种机制叫做克隆,如果定义了 __clone()方法,则新创建的对象(复制生成的对象)中的 __clone()方法会被调用。
程序员可以通过克隆把对象进行整体的克隆,但是有时我们不希望别人克隆我们的对象,比如单列模式,这时使用克隆可以解决。

示例:

<?php

class Cat{
    public $name;
    public $age;

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

    public function showInfo(){
        echo '姓名是:' . $name . ' ' . '年龄是:' . $age; 
    }

    private function __clone(){

    }

}
$cat = new Cat('小花',2);
echo '<pre>';
var_dump($cat);
$cat2 = clone $cat;
var_dump($cat2);

注意在这里魔术方法的权限修饰符是private,私有的。

__tostring()

__tostring方法用于一个类被当成字符串时应怎样回应。例如 echo $obj;

当我们尝试把一个对象当成字符换进行echo输出的时候,类的tostring方法就会默认被调用,在这个方法中我们可以定义对象应该输出什么。

示例:

<?php
class Dog{
    private $name;
    private $age;
    private $color;

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

    //定义tostring方法
    public function __toString(){
        return  '名字是:' . $this ->name . ' ' . '年龄是:' . $this -> age . ' ' . '颜色是:' . $this ->color;
    }
}
$dog = new Dog('小白',4,'red');
echo $dog;

注意:在tostring中必须要有一个返回值。

__construct()

__construct():PHP 5 允行开发者在一个类中定义一个方法作为构造函数。具有构造函数的类会在每次创建新对象时先调用此方法。

在类中定义构造函数一般是完成创建对象时,对象的初始化。当我们没有定义构造方法的时候,系统会调用他自己默认的构造函数,这个构造函数是一个无参的构造函数。

示例

<?php

class Cat{
protected $name;
protected $age;
protected $sex;

//定义一个构造函数,完成对属性的初始化。
    public function __construct($name,$age,$sex){
        $this -> name = $name;
        $this -> age = $age;
        $this -> sex = $sex;
    }
}

$cat = new Cat('小白',12,'雄');
echo '<pre>';
var_dump($cat);

__destruct()

__destruct();PHP 5 引入了析构函数的概念,析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行。

析构函数会在函数销毁前执行,在这里面我们可以对用到的资源进行释放,比如数据库。

示例

<?php
    class DaoMysql{
        protected $link;

        public function __construct($host,$user,$pwd){
            $this -> link = @mysql_connect($host,$user,$pwd);
        }

        public function getLink(){
            return $this -> link;
        }

        //析构函数,用来释放数据库资源。
        public function __destruct(){
            mysql_close($this->link);
        }
    }

    $daoMysql = new DaoMysql('localhost','root','123456');

    $sql = 'select * from tb1';
    mysql_select_db('test');
    mysql_query('set names utf8');
    //通过对象的到里面的链接对象。
    $res = mysql_query($sql,$daoMysql -> getLink());

    echo '<pre>';
    while($row = mysql_fetch_assoc($res)){
        var_dump($row);
    }
    //当类中没有析构函数的时候,把对象置为空,下面的获取数据还能执行,
    //当类中有析构函数的时候,把对象置为空,下面的获取数据会出错。说明成功的在析构方法中把数据库连接释放掉了。
    $daoMysql = null;

    $res = mysql_query($sql);
    echo '<pre>';
    while($row = mysql_fetch_assoc($res)){
        var_dump($row);
    }

总结

在php中,这些魔术方法大多数都是我们操作不可操作的数据时,系统触发执行。区别于别的语言,也可以说是php的一大特色。(- _ -);

相关文章