note 123653 added to class.arrayaccess

From: Date: Mon, 04 Mar 2019 21:41:37 +0000
Subject: note 123653 added to class.arrayaccess
Groups: php.notes 
Request: Send a blank email to php-notes+get-210318@lists.php.net to get a copy of this message
You might be wondering whether implementing an ArrayAccess interface makes the class iterable. It is, after all, an "array". The answer is no, it doesn't. Additionally there are a couple of subtle gotchas if you add both and want it to be an associate array. The below is a class that has both ArrayAccess AND Iterator interfaces. And Countable as well just to be complete. <?php //This uses return types which are only valid in PHP 7. They can be removed if you are forced to use an older version of PHP. //N.b. The offsetSet method contains a function that is only valid from PHP 7.3 onwards. class HandyClass implements ArrayAccess, Iterator, Countable { private $container = array(); //An Array of your actual values. private $keys = array(); //We use a separate array of keys rather than $this->position directly so that we can private $position; //have an associative array. public function __construct() { $position = 0; $this->container = array( //Arbitrary array for demo. You probably want to set this to empty in practice or "a" => 1, //get it from somewhere else, e.g. passing it into the constructor. "b" => 2, "c" => 3, ); $this->keys = array_keys($this->container); } public function count() : int { //This is necessary for the Countable interface. It could as easily return return count($this->keys); //count($this->container). The number of elements will be the same. } public function rewind() { //Necessary for the Iterator interface. $this->position shows where we are in our list of $this->position = 0; //keys. Remember we want everything done via $this->keys to handle associative arrays. } public function current() { //Necessary for the Iterator interface. return $this->container[$this->keys[$this->position]]; } public function key() { //Necessary for the Iterator interface. return $this->keys[$this->position]; } public function next() { //Necessary for the Iterator interface. ++$this->position; } public function valid() { //Necessary for the Iterator interface. return isset($this->keys[$this->position]); } public function offsetSet($offset, $value) { //Necessary for the ArrayAccess interface. if(is_null($offset)) { $this->container[] = $value; $this->keys[] = array_key_last($this->container); //THIS IS ONLY VALID FROM php 7.3 ONWARDS. See note below for alternative. } else { $this->container[$offset] = $value; if(!in_array($offset, $this->keys)) $this->keys[] = $offset; } } public function offsetExists($offset) { return isset($this->container[$offset]); } public function offsetUnset($offset) { unset($this->container[$offset]); unset($this->keys[array_search($offset,$this->keys)]); $this->keys = array_values($this->keys); //This line re-indexes the array of container keys because if someone } //deletes the first element, the rewind to position 0 when iterating would //cause no element to be found. public function offsetGet($offset) { return isset($this->container[$offset]) ? $this->container[$offset] : null; } } ?> Example usages: <?php $myClass = new HandyClass(); echo('Number of elements: ' . count($myClass) . "\n\n"); echo("Foreach through the built in test elements:\n"); foreach($myClass as $key => $value) { echo("$value\n"); } echo("\n"); $myClass['d'] = 4; $myClass['e'] = 5; echo('Number of elements after adding two: ' . count($myClass) . "\n\n"); unset($myClass['a']); echo('Number of elements after removing one: ' . count($myClass) . "\n\n"); echo("Accessing an element directly:\n"); echo($myClass['b'] . "\n\n"); $myClass['b'] = 5; echo("Foreach after changing an element:\n"); foreach($myClass as $key => $value) { echo("$value\n"); } echo("\n"); ?> ---- Server IP: 208.43.231.9 Probable Submitter: 185.85.3.194 (proxied: 92.27.142.131) ---- Manual Page -- http://php.net/manual/en/class.arrayaccess.php Edit -- https://master.php.net/note/edit/123653 Del: integrated -- https://master.php.net/note/delete/123653/integrated Del: useless -- https://master.php.net/note/delete/123653/useless Del: bad code -- https://master.php.net/note/delete/123653/bad+code Del: spam -- https://master.php.net/note/delete/123653/spam Del: non-english -- https://master.php.net/note/delete/123653/non-english Del: in docs -- https://master.php.net/note/delete/123653/in+docs Del: other reasons-- https://master.php.net/note/delete/123653 Reject -- https://master.php.net/note/reject/123653 Search -- https://master.php.net/manage/user-notes.php

« previous php.notes (#210318) next »