Question
Problem:
ArrayObject works as expected when the values are set or read manually, but when using a function (foreach for example) to iterate over it, things gets wicked.
It doesn't call the offset* methods that I have defined but instead uses the ArrayIterator methods.
Code:
The Class:
class obsecureArray extends ArrayObject {
public function offsetSet($name, $value) {
call_user_func_array(array('parent', __FUNCTION__), array(base64_encode($name), base64_encode($value)) );
}
public function offsetGet($name) {
return base64_decode( call_user_func_array(array('parent', __FUNCTION__), (array) base64_encode($name) ) );
}
public function offsetExists($name) {
return call_user_func_array(array('parent', __FUNCTION__), (array) base64_encode($name) );
}
public function offsetUnset($name) {
return call_user_func_array(array('parent', __FUNCTION__), (array) base64_encode($name) );
}
}
Usage Example:
$a = new obsecureArray();
$a['test'] = 'Value';
$a[2] = '1';
define('BR','<br />');
echo 'test: ',$a['test'],BR,'2: ',$a[2],BR;
foreach($a as $key => $value)
echo 'Key: ',$key,' Value:',$value,BR;
Output:
test: Value
2: 1
Key: dGVzdA== Value:VmFsdWU=
Key: Mg== Value:MQ==
La solution
I look into the ArrayObject __construct
method documentation and found the third argument related to my problem:
iterator_class:
Specify the class that will be used for iteration of the ArrayObject object. ArrayIterator is the default class used.
Now I could extended an ArrayIterator
with my own offset*
methods and pass it to my the constructor of ArrayObject
, So I looked into ArrayIterator
and it was almost identical to the ArrayObject
except that it wasn't using an external iterator obviously. So All I had to do was extend ArrayIterator
instead. and had to override the current
and key
method as well.
So that I have:
class obsecureArray extends ArrayIterator {
public function offsetSet($name, $value) {
call_user_func_array(array('parent', __FUNCTION__), array(base64_encode($name), base64_encode($value)));
}
public function offsetGet($name) {
return base64_decode(call_user_func_array(array('parent', __FUNCTION__), (array) base64_encode($name)));
}
public function offsetExists($name) {
return call_user_func_array(array('parent', __FUNCTION__), (array) base64_encode($name));
}
public function offsetUnset($name) {
return call_user_func_array(array('parent', __FUNCTION__), (array) base64_encode($name));
}
public function key() {
return base64_decode(parent::key());
}
public function current() {
return base64_decode(parent::current());
}
}
and it works perfectly as expected.
and for:
$a = new obsecureArray();
$a['test'] = 'Value';
$a[2] = '1';
define('BR','<br />');
echo 'test: ',$a['test'],BR,'2: ',$a[2],BR;
foreach($a as $key => $value)
echo 'Key: ',$key,' Value:',$value,BR;
I got:
test: Value 2: 1 Key: test Value:Value Key: 2 Value:1
Autres conseils
You'll want to implement Iterator or IteratorAggregate. You have more control over the former, but the latter is simpler to implement (probably with more overhead):
class People implements IteratorAggregate {
protected $children;
// ...
public function getIterator() {
return new ArrayIterator( $this->children );
}
}
See the Iterator for boilerplate methods for that interface.
In my opinion your code works as expected, if you want to make sure that your values handled properly use correct methods:
$a = new obsecureArray();
$a->offsetSet('test', 'Value');
$a->offsetSet(2, '1');
also instead of
define('BR','
');
there is predefined php property PHP_EOL
You'll need to set a custom iterator class:
<?php
class SecureArray extends ArrayObject {
public function __construct($array = array()) {
parent::__construct($array);
$this->setIteratorClass('SecureIterator');
}
public function offsetSet($name, $value) {
parent::offsetSet( base64_encode($name), base64_encode($value) );
}
public function offsetGet($name) {
return base64_decode( parent::offsetGet( base64_encode($name) ) );
}
public function offsetExists($name) {
return parent::offsetExists( base64_encode($name) );
}
public function offsetUnset($name) {
return parent::offsetUnset( base64_encode($name) );
}
}
class SecureIterator extends ArrayIterator {
function current() {
return base64_decode(parent::current());
}
function key() {
return base64_decode(parent::key());
}
}