重載

PHP所提供的重載(overloading)是指動(dòng)態(tài)地創(chuàng)建類(lèi)屬性和方法。我們是通過(guò)魔術(shù)方法(magic methods)來(lái)實(shí)現(xiàn)的。

當(dāng)調(diào)用當(dāng)前環(huán)境下未定義或不可見(jiàn)的類(lèi)屬性或方法時(shí),重載方法會(huì)被調(diào)用。本節(jié)后面將使用不可訪(fǎng)問(wèn)屬性(inaccessible properties)不可訪(fǎng)問(wèn)方法(inaccessible methods)來(lái)稱(chēng)呼這些未定義或不可見(jiàn)的類(lèi)屬性或方法。

所有的重載方法都必須被聲明為 public

注意:

這些魔術(shù)方法的參數(shù)都不能通過(guò)引用傳遞

注意:

PHP中的重載與其它絕大多數(shù)面向?qū)ο笳Z(yǔ)言不同。傳統(tǒng)的重載是用于提供多個(gè)同名的類(lèi)方法,但各方法的參數(shù)類(lèi)型和個(gè)數(shù)不同。

屬性重載

public __set(string $name, mixed $value): void
public __get(string $name): mixed
public __isset(string $name): bool
public __unset(string $name): void

在給不可訪(fǎng)問(wèn)(protected 或 private)或不存在的屬性賦值時(shí),__set() 會(huì)被調(diào)用。

讀取不可訪(fǎng)問(wèn)(protected 或 private)或不存在的屬性的值時(shí),__get() 會(huì)被調(diào)用。

當(dāng)對(duì)不可訪(fǎng)問(wèn)(protected 或 private)或不存在的屬性調(diào)用 isset()empty() 時(shí),__isset() 會(huì)被調(diào)用。

當(dāng)對(duì)不可訪(fǎng)問(wèn)(protected 或 private)或不存在的屬性調(diào)用 unset() 時(shí),__unset() 會(huì)被調(diào)用。

參數(shù) $name 是指要操作的變量名稱(chēng)。__set() 方法的 $value 參數(shù)指定了 $name 變量的值。

屬性重載只能在對(duì)象中進(jìn)行。在靜態(tài)方法中,這些魔術(shù)方法將不會(huì)被調(diào)用。所以這些方法都不能被 聲明為 static。將這些魔術(shù)方法定義為 static 會(huì)產(chǎn)生一個(gè)警告。

注意:

因?yàn)?PHP 處理賦值運(yùn)算的方式,__set() 的返回值將被忽略。類(lèi)似的, 在下面這樣的鏈?zhǔn)劫x值中,__get() 不會(huì)被調(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;

     
/**  只有從類(lèi)外部訪(fǎng)問(wèn)這個(gè)屬性時(shí),重載才會(huì)發(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->1;
echo 
$obj->"\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";
?>

以上例程會(huì)輸出:

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

方法重載

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

在對(duì)象中調(diào)用一個(gè)不可訪(fǎng)問(wèn)方法時(shí),__call() 會(huì)被調(diào)用。

在靜態(tài)上下文中調(diào)用一個(gè)不可訪(fǎng)問(wèn)方法時(shí),__callStatic() 會(huì)被調(diào)用。

$name 參數(shù)是要調(diào)用的方法名稱(chēng)。$arguments 參數(shù)是一個(gè)枚舉數(shù)組,包含著要傳遞給方法 $name 的參數(shù)。

示例 #2 使用 __call()__callStatic() 對(duì)方法重載

<?php
class MethodTest 
{
    public function 
__call($name$arguments
    {
        
// 注意: $name 的值區(qū)分大小寫(xiě)
        
echo "Calling object method '$name' "
             
implode(', '$arguments). "\n";
    }

    public static function 
__callStatic($name$arguments
    {
        
// 注意: $name 的值區(qū)分大小寫(xiě)
        
echo "Calling static method '$name' "
             
implode(', '$arguments). "\n";
    }
}

$obj = new MethodTest;
$obj->runTest('in object context');

MethodTest::runTest('in static context');
?>

以上例程會(huì)輸出:

Calling object method 'runTest' in object context
Calling static method 'runTest' in static context