note 123653 added to class.arrayaccess
| From: | TaliesinNuinpublic at taliesinnuin dot net | 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