php面向對象之重載(overloading)

在java中,重載就是函數或者方法有相同的名稱,但是參數列表不相同的情形,這樣的同名不同參數的函數或者方法之間,互相稱之爲重載函數或者方法,這也牽涉到了多態。

在PHP中呢,有人說php沒有多態,那重載呢?

PHP所提供的"重載"(overloading)是指動態地"創建"類屬性和方法,分爲屬性的重載和方法的重載;

我們是通過魔術方法(magic methods)來實現的,當調用當前環境下未定義或不可見的類屬性或方法時,重載方法會被調用。本節後面將使用"不可訪問屬性(inaccessible properties)"和"不可訪問方法(inaccessible methods)"來稱呼這些未定義或不可見的類屬性或方法。

屬性重載

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()會被調用。

__get()方法,有兩個參數,$name是指要操作的變量名稱(另外三個都是這個意思),$value是指對應name的值。

一個很簡單的例子:

class Person {
    public $name;
    private $age;

    public function __set($name, $value)
    {
        echo "你賦值的屬性{$name}不存在";
    }

    public function __get($name)
    {
        echo "你所訪問的屬性{$name}不存在";
    }

    public function __isset($name)
    {
        echo "你判斷的屬性{$name}不存在";
    }

    public function __unset($name)
    {
        echo "你銷燬的屬性{$name}不存在";
    }
}

$person = new Person();
echo '賦值操作:',$person->gender = 'nale',<br />';
echo '取值操作:',$person->gender,'<br />';
echo 'isset判斷操作:',isset($person->gender),'<br />';
echo 'empty判斷操作:',empty($person->gender),'<br />';
echo 'empty判斷操作:',empty($person->gender),'<br />';
echo 'unset操作:';unset($person->gender);
結果如下:


empty這裏後面有個1是因爲當前返回的是true,輸出來就是1了;

當然,大家也會發現,沒有這些魔術方法,我照樣可以跑通,我把這些魔術方法註釋掉:

class Person {
    public $name;
    private $age;

//    public function __set($name, $value)
//    {
//        echo "你賦值的屬性{$name}不存在";
//    }
//
//    public function __get($name)
//    {
//        echo "你所訪問的屬性{$name}不存在";
//    }
//
//    public function __isset($name)
//    {
//        echo "你判斷的屬性{$name}不存在";
//    }
//
//    public function __unset($name)
//    {
//        echo "你銷燬的屬性{$name}不存在";
//    }
//
//    public function __call($name, $arguments)
//    {
//        echo '你在調用不存在的方法';
//    }
}

$person = new Person();
echo '賦值操作:',$person->gender = 123,'<br />';
echo '取值操作:',$person->gender,'<br />';
echo 'isset判斷操作:',isset($person->gender),'<br />';
echo 'empty判斷操作:',empty($person->gender),'<br />';
echo 'empty判斷操作:',empty($person->gender),'<br />';
echo 'unset操作:';unset($person->gender);
echo '取值操作:',$person->gender,'<br />'; //訪問不存在的屬性,因爲被銷燬了,應該會報一個notic級別的錯誤

運行如下所示:


這個是因爲在PHP中,並沒有強制屬性都在類中聲明,這是動態的給對象屬性賦值,在其它強類型語言中,可能行不通,所以在一般時候,並不建議這樣寫。

那如果有這種動態增加值的需求的時候怎麼辦呢,我們可以利用屬性的重載來完成,如下:

class Person {
    public $name;
    private $age;
    private $_attr = array();

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

    public function __get($name)
    {
        if($this->_attr[$name]){
            return $this->_attr[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        $this->_attr[$name] = $value;
    }

    public function __isset($name)
    {
        return isset($this->_attr[$name]);
    }
    public function __unset($name)
    {
        unset($this->_attr[$name]);
    }
}

$person = new Person('lightWay', 24);

//賦值操作
$person->gender = 'male';
$person->home = 'hubei';

echo $person->home; //取值操作
unset($person->home); //銷燬操作

方法重載

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

在對象中調用一個不可訪問方法時,__call() 會被調用。


在靜態上下文中調用一個不可訪問方法時,__callStatic() 會被調用。

$name 參數是要調用的方法名稱。$arguments 參數是一個枚舉數組,包含着要傳遞給方法 $name 的參數。

上代碼說明吧:

class Person {
    public function __call($name, $arguments)
    {
        echo '您正在調用一個不存在的方法',self::class,'::',$name,PHP_EOL;
        print_r($arguments);
    }

    public static function __callStatic($name, $arguments)
    {
        echo '您正在調用一個不存在的靜態方法',self::class,'::',$name,PHP_EOL;
        print_r($arguments);
    }
}

$person = new Person();
$person->sayMyInfo1('123',2,true);
$person::show(1,2,3);
執行結果如下:



我們可以用PHP中的重載,去模擬其他語言中的重載,代碼如下:

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

    public function __call($name, $arguments)
    {
        if($name == 'eating') {
            switch (count($arguments)) {
                case 1 :
                    echo "{$this->name}正在用{$arguments[0]}喫中餐",PHP_EOL;
                    break;
                case 2 :
                    echo "{$this->name}正在用{$arguments[0]}和{$arguments[1]}喫西餐",PHP_EOL;
                    break;
                case 0:
                default:
                    echo "{$this->name}在喝西北風",PHP_EOL;
                    break;
            }
        } else {
            echo '您訪問的方法不存在';
        }
    }


}

$my = new Person('lightWay');

$my->eating('筷子');

$my->eating('刀','叉子');

$my->eating();

執行結果如下:


這裏只是用了參數的不同,來執行不同的動作,可以利用的點很多,很多框架都會到這個,好吧,這裏就完了,看完了,你還覺得PHP沒用多態嗎?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章