Search code examples
phpiterationarrayaccess

Arrayaccess, Iterator and current()


I have class which implements Countable, ArrayAccess, Iterator and Serializable. I have a public varibale $data, in array form. And my iteration implementions:

public function rewind() { return reset($this->data); }
public function current() { return current($this->data); }
public function key() { return key($this->data); }
public function next() { return next($this->data); }
public function valid() { return isset($this->data[$this->key()]); }

Well everything works with foreach loop, but if i manually call current($arrayObject), it returns whole $data array, not teh current in it. I can do current($arrayObject->data), but like to keep native array functionality as where i can.

This is php behavior right? (not mine code bug) And is there any workaround this, without custom function(fingers crossed)?

[EDIT] Simplified version of full class(working):

$arrayObject = mysqli_fetch_object($this->result_id, "simpleMysqliResult ", array(array(
        "fields" => array( "field1", "field2", "field3" )
    )));
class simpleMysqliResult implements Countable, ArrayAccess, Iterator, Serializable {

    public $data = array();

    public function __construct($input) {
        extract($input);
        foreach ($fields as $field) {
            $this->data[$field] = $this->{$field};
            unset($this->{$field});
        }
    }

    public function &toArray() { return $this->data; }
    public function offsetGet($index) { return $this->data[$index]; }
    public function offsetSet($index, $value) { $this->data[$index] = $value; }
    public function offsetUnset($index) { unset($this->data[$index]); }
    public function offsetExists($index) { return $this->offsetGet($index) !== null; }
    public function count() { return count($this->data); }
    public function rewind() { return reset($this->data); }
    public function current() { return current($this->data); }
    public function key() { return key($this->data); }
    public function next() { return next($this->data); }
    public function valid() { return isset($this->data[$this->key()]); }
    public function serialize() { return serialize($this->data); }
    public function unserialize($str) { return $this->data = unserialize($str); }

    public function __call($func, $argv) {
        if (!is_callable($func) || substr($func, 0, 6) !== 'array_')
        {
            throw new BadMethodCallException(__CLASS__.'->'.$func);
        }
        return call_user_func_array($func, array_merge(array($this->data), $argv));
    }

}

Solution

  • Try placing your data in private mode. I suspect you have an external procedure playing around with it and making changes to it. I copied your class and altered your constructor a bit since i didn't have the same input as you and i get no strange behavior. Ultimately, you might want to look into why you extract($input) also, just use $input['fields'] or $input->fields as you see fit, it'll still work.

    Here are my corrections:

    private $data = array();
    
    public function __construct($input) {
        foreach($input['fields'] as $field) {
            $this->data[$field] = $input[$field];
        }
    }
    

    Here are my tests

    $data = array('fields' => array('id', 'name'), 'id' => 1, 'name' => 'Franco');
    $smr = new simpleMysqliResult($data);
    var_dump($smr->current());
    var_dump($smr->current());
    var_dump($smr->current());
    var_dump($smr->current());
    var_dump($smr->next());
    var_dump($smr->current());
    var_dump($smr->current());
    

    And my output is ok

    int(1) int(1) int(1) int(1) string(6) "Franco" string(6) "Franco" string(6) "Franco" 
    

    So like i said, i think your problem mainly lies in the fact that your $data is public and something else is playing with it.

    OR

    It lies in your constructor that i had to fix to make it work on my side.

    Good luck