1. 程式人生 > >php面向物件之過載(overloading)

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沒用多型嗎?