PHP所提供的重載
(overloading)是指動態(tài)地創(chuàng)建
類屬性和方法。我們是通過魔術(shù)方法(magic methods)來實(shí)現(xiàn)的。
當(dāng)調(diào)用當(dāng)前環(huán)境下未定義或不可見的類屬性或方法時,重載方法會被調(diào)用。本節(jié)后面將使用不可訪問屬性(inaccessible
properties)
和不可訪問方法(inaccessible
methods)
來稱呼這些未定義或不可見的類屬性或方法。
所有的重載方法都必須被聲明為 public
。
注意:
這些魔術(shù)方法的參數(shù)都不能通過引用傳遞。
注意:
PHP中的
重載與其它絕大多數(shù)面向?qū)ο笳Z言不同。傳統(tǒng)的重載是用于提供多個同名的類方法,但各方法的參數(shù)類型和個數(shù)不同。
$name
): bool$name
): void在給不可訪問(protected 或 private)或不存在的屬性賦值時,__set() 會被調(diào)用。
讀取不可訪問(protected 或 private)或不存在的屬性的值時,__get() 會被調(diào)用。
當(dāng)對不可訪問(protected 或 private)或不存在的屬性調(diào)用 isset() 或 empty() 時,__isset() 會被調(diào)用。
當(dāng)對不可訪問(protected 或 private)或不存在的屬性調(diào)用 unset() 時,__unset() 會被調(diào)用。
參數(shù) $name 是指要操作的變量名稱。__set() 方法的 $value 參數(shù)指定了 $name 變量的值。
屬性重載只能在對象中進(jìn)行。在靜態(tài)方法中,這些魔術(shù)方法將不會被調(diào)用。所以這些方法都不能被
聲明為 static。將這些魔術(shù)方法定義為 static
會產(chǎn)生一個警告。
注意:
因?yàn)?PHP 處理賦值運(yùn)算的方式,__set() 的返回值將被忽略。類似的, 在下面這樣的鏈?zhǔn)劫x值中,__get() 不會被調(diào)用:
$a = $obj->b = 8;
示例 #1 使用 __get(),__set(),__isset() 和 __unset() 進(jìn)行屬性重載
<?php
class PropertyTest {
/** 被重載的數(shù)據(jù)保存在此 */
private $data = array();
/** 重載不能被用在已經(jīng)定義的屬性 */
public $declared = 1;
/** 只有從類外部訪問這個屬性時,重載才會發(fā)生 */
private $hidden = 2;
public function __set($name, $value)
{
echo "Setting '$name' to '$value'\n";
$this->data[$name] = $value;
}
public function __get($name)
{
echo "Getting '$name'\n";
if (array_key_exists($name, $this->data)) {
return $this->data[$name];
}
$trace = debug_backtrace();
trigger_error(
'Undefined property via __get(): ' . $name .
' in ' . $trace[0]['file'] .
' on line ' . $trace[0]['line'],
E_USER_NOTICE);
return null;
}
public function __isset($name)
{
echo "Is '$name' set?\n";
return isset($this->data[$name]);
}
public function __unset($name)
{
echo "Unsetting '$name'\n";
unset($this->data[$name]);
}
/** 非魔術(shù)方法 */
public function getHidden()
{
return $this->hidden;
}
}
echo "<pre>\n";
$obj = new PropertyTest;
$obj->a = 1;
echo $obj->a . "\n\n";
var_dump(isset($obj->a));
unset($obj->a);
var_dump(isset($obj->a));
echo "\n";
echo $obj->declared . "\n\n";
echo "Let's experiment with the private property named 'hidden':\n";
echo "Privates are visible inside the class, so __get() not used...\n";
echo $obj->getHidden() . "\n";
echo "Privates not visible outside of class, so __get() is used...\n";
echo $obj->hidden . "\n";
?>
以上例程會輸出:
Setting 'a' to '1' Getting 'a' 1 Is 'a' set? bool(true) Unsetting 'a' Is 'a' set? bool(false) 1 Let's experiment with the private property named 'hidden': Privates are visible inside the class, so __get() not used... 2 Privates not visible outside of class, so __get() is used... Getting 'hidden' Notice: Undefined property via __get(): hidden in <file> on line 70 in <file> on line 29
在對象中調(diào)用一個不可訪問方法時,__call() 會被調(diào)用。
在靜態(tài)上下文中調(diào)用一個不可訪問方法時,__callStatic() 會被調(diào)用。
$name 參數(shù)是要調(diào)用的方法名稱。$arguments 參數(shù)是一個枚舉數(shù)組,包含著要傳遞給方法 $name 的參數(shù)。
示例 #2 使用 __call() 和 __callStatic() 對方法重載
<?php
class MethodTest
{
public function __call($name, $arguments)
{
// 注意: $name 的值區(qū)分大小寫
echo "Calling object method '$name' "
. implode(', ', $arguments). "\n";
}
public static function __callStatic($name, $arguments)
{
// 注意: $name 的值區(qū)分大小寫
echo "Calling static method '$name' "
. implode(', ', $arguments). "\n";
}
}
$obj = new MethodTest;
$obj->runTest('in object context');
MethodTest::runTest('in static context');
?>
以上例程會輸出:
Calling object method 'runTest' in object context Calling static method 'runTest' in static context