重載

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

當調(diào)用當前環(huán)境下未定義或不可見的類屬性或方法時,重載方法會被調(diào)用。本節(jié)后面將使用不可訪問屬性(inaccessible properties)不可訪問方法(inaccessible methods)來稱呼這些未定義或不可見的類屬性或方法。

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

注意:

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

注意:

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

屬性重載

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

在給不可訪問(protected 或 private)或不存在的屬性賦值時,__set() 會被調(diào)用。

讀取不可訪問(protected 或 private)或不存在的屬性的值時,__get() 會被調(diào)用。

當對不可訪問(protected 或 private)或不存在的屬性調(diào)用 isset()empty() 時,__isset() 會被調(diào)用。

當對不可訪問(protected 或 private)或不存在的屬性調(diào)用 unset() 時,__unset() 會被調(diào)用。

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

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

注意:

因為 PHP 處理賦值運算的方式,__set() 的返回值將被忽略。類似的, 在下面這樣的鏈式賦值中,__get() 不會被調(diào)用:

 $a = $obj->b = 8; 

示例 #1 使用 __get(),__set()__isset()__unset() 進行屬性重載

<?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->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";
?>

以上例程會輸出:

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

在對象中調(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