簡體   English   中英

PHP中的ArrayAccess - 通過引用分配偏移量

[英]ArrayAccess in PHP — assigning to offset by reference

首先,來自ArrayAccess::offsetSet()的ole'手冊的引用:

此函數不是通過引用在賦值中調用,也不是通過ArrayAccess重載的數組維度的間接更改(在某種意義上是間接的,不是通過直接更改維度,而是通過更改子維度或子屬性或分配數組維度通過引用另一個變量)。 而是調用ArrayAccess :: offsetGet() 只有當該方法通過引用返回時,操作才會成功,這只能從PHP 5.3.4開始

我有點困惑。 看來這表明( 從5.3.4開始 )可以定義offsetGet()以在實現類中通過引用返回,從而通過引用處理賦值。

所以,現在是一個測試片段:

忽略沒有驗證和isset()檢查

class Test implements ArrayAccess
{
    protected $data = array();

    public function &offsetGet($key)
    {
        return $this->data[$key];
    }

    public function offsetSet($key, $value)
    {
        $this->data[$key] = $value;
    }

    public function offsetExists($key) { /* ... */ }

    public function offsetUnset($key) { /* ... */ }

}

$test = new Test();

$test['foo'] = 'bar';
$test['foo'] = &$bar; // Fatal error: Cannot assign by reference to
                      // overloaded object in

var_dump($test, $bar);    

好的,所以這不起作用。 那么這本手冊中的內容是指什么?

原因
我想允許通過數組運算符通過引用分配給實現ArrayAccess的對象,如示例代碼段所示。 我之前已經對此進行了調查,我認為這不可能,但由於不確定性而又回到了這一點,我( 重新 )在手冊中發現了這一點。 現在我只是困惑。


更新 :當我點擊發布你的問題時 ,我意識到這可能只是通過引用另一個變量來引用賦值,例如$bar = &$test['foo']; 如果是這樣,那么道歉; 雖然知道如果可能的話,通過引用分配給重載的對象將是很好的。


進一步闡述 :歸結為什么,我希望有以下方法別名:

isset($obj[$key]);       // $obj->has_data($key);

$value = $obj[$key];     // $obj->get_data($key);

$obj[$key] = $value;     // $obj->set_data($key, $value);

$obj[$key] = &$variable; // $obj->bind_data($key, $variable);

// also, flipping the operands is a syntactic alternative
$variable = &$obj[$key]; // $obj->bind_data($key, $variable);

unset($obj[$key]);       // $obj->remove_data($key);

至於hasgetsetremove去,他們有支持的方法沒有問題ArrayAccess 綁定功能是我不知所措的地方,我開始接受ArrayAccess和PHP的限制只是禁止這一點。

手冊所指的是所謂的“間接修改”。 請考慮以下腳本:

$array = new ArrayObject;
$array['foo'] = array();
$array['foo']['bar'] = 'foobar';

在上面的腳本中, $array['foo'] = array(); 將觸發offsetSet('foo', array()) $array['foo']['bar'] = 'foobar'; 另一方面會觸發offsetGet('foo') 為什么這樣? 最后一行將在引擎蓋下大致評估:

$tmp =& $array['foo'];
$tmp['bar'] = 'foobar';

所以$array['foo']首先由ref獲取然后修改。 如果你的offsetGet由ref返回,那么這將成功。 如果不是,你會得到一些間接修改錯誤。


另一方面,您想要的恰恰相反:不通過引用獲取值,而是分配它。 理論上這需要offsetSet($key, &$value)的簽名,但實際上這是不可能的

順便說一句,參考文獻很難掌握。 您將獲得許多非顯而易見的行為,對於數組項引用(尤其是那些具有一些特殊規則)尤其如此。 我建議你完全避開它們。

這不適用於ArrayAccess ,你可以添加一個公共函數,允許你設置一個偏移量的引用(當然,這看起來與使用數組語法不同,所以它不是一個足夠的答案):

class Test implements ArrayAccess{

    protected $_data = array();

    public function &offsetGet($key){
        return $this->_data[$key];
    }

    ... 

    public function offsetSetReference($key, &$value)
    {
        $this->_data[$key] = &$value;
    }
}

$test = new Test();
$test['foo'] = $var = 'bar';
$test->offsetSetReference('bar', $var);    
$var = 'foo';    
echo $test['bar']; # foo    
$alias = &$test['bar'];    
$alias = 'hello :)';    
echo $var; # hello :)

可能在首次實現ArrayAccess時忘記了這樣的功能。

編輯:將其作為“參考作業”傳遞:

class ArrayAccessReferenceAssignment
{
    private $reference;
    public function __construct(&$reference)
    {
        $this->reference = &$reference;
    }
    public function &getReference()
    {
        $reference = &$this->reference;
        return $reference;
    }
}


class Test implements ArrayAccess{
    ...
    public function offsetSet($key, $value){
        if ($value instanceof ArrayAccessReferenceAssignment)
        {
           $this->offsetSetReference($key, $value->getReference());
        }
        else
        {
           $this->_data[$key] = $value;
        }
    }

然后,因為你實現了它,它可以完美地工作。 這可能比上面更明確的offsetSetReference變種更好地接口:

$test = new Test();
$test['foo'] = $var = 'bar';
$test['bar'] = new ArrayAccessReferenceAssignment($var);

$var = 'foo';
echo $test['bar']; # foo
$alias = &$test['bar'];
$alias = 'hello :)';
echo $var; # hello :)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM