[英]PHP ArrayAccess - multidimensional array and offsetGet with reference
[英]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);
至於has
, get
, set
和remove
去,他們有支持的方法沒有問題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.