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==

CodePad example.

Was it helpful?

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

CodePad example

OTHER TIPS

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());
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top