$myArray = array (\'SOmeKeyNAme\' => 7);
I want $myArray[\'somekeyname\']
to return 7
.
Is there a way to do this
A simple, but maybe expensive way, is to make a copy, then use array_change_key_case($array_copy, CASE_LOWER)
, and after that access array_copy['somekeyname']
I combined Paul Dixon's idea of creating a mapping for the keys and Kendall Hopkins' idea of using the ArrayAccess interface for retaining the familiar way of accessing a PHP array.
The result is a class that avoids copying the initial array and allows transparent case-insensitive access, while internally preserving the keys' case. Limitation: If case-insensitively equal keys (e.g. 'Foo' and 'foo') are contained in the initial array or are added dynamically, then latter entries will overwrite previous ones (rendering these inaccessible).
Admittedly, in many cases its (imo) much more straight-forward to just lowercase the keys by $lowercasedKeys = array_change_key_case($array, CASE_LOWER);
, as suggested by Mikpa.
The CaseInsensitiveKeysArray class
class CaseInsensitiveKeysArray implements ArrayAccess
{
private $container = array();
private $keysMap = array();
public function __construct(Array $initial_array = array())
{
$this->container = $initial_array;
$keys = array_keys($this->container);
foreach ($keys as $key)
{
$this->addMappedKey($key);
}
}
public function offsetSet($offset, $value)
{
if (is_null($offset))
{
$this->container[] = $value;
}
else
{
$this->container[$offset] = $value;
$this->addMappedKey($offset);
}
}
public function offsetExists($offset)
{
if (is_string($offset))
{
return isset($this->keysMap[strtolower($offset)]);
}
else
{
return isset($this->container[$offset]);
}
}
public function offsetUnset($offset)
{
if ($this->offsetExists($offset))
{
unset($this->container[$this->getMappedKey($offset)]);
if (is_string($offset))
{
unset($this->keysMap[strtolower($offset)]);
}
}
}
public function offsetGet($offset)
{
return $this->offsetExists($offset) ?
$this->container[$this->getMappedKey($offset)] :
null;
}
public function getInternalArray()
{
return $this->container;
}
private function addMappedKey($key)
{
if (is_string($key))
{
$this->keysMap[strtolower($key)] = $key;
}
}
private function getMappedKey($key)
{
if (is_string($key))
{
return $this->keysMap[strtolower($key)];
}
else
{
return $key;
}
}
}
You can lowercase your keys when assigning them to the array and also lowercase them when looking up the value.
Without modifying the array, but the whole data structure:
A really cumbersome way involves creating magic getter/setter methods, but would it really be worth the effort (note that the other methods have to be implemented too)?
<?php
class CaseInsensitiveArray
{
protected $m_values;
public function __construct()
{
$this->m_values = array();
}
public function __get($key)
{
return array_key_exists($key, $this->m_values) ? $this->m_values[$key] : null;
}
public function __set($key, $value)
{
$this->m_attributes[$key] = $value;
}
}
You could use ArrayAccess interface to create a class that works with array syntax.
Example
$lower_array_object = new CaseInsensitiveArray;
$lower_array_object["thisISaKEY"] = "value";
print $lower_array_object["THISisAkey"]; //prints "value"
or
$lower_array_object = new CaseInsensitiveArray(
array( "SoMeThInG" => "anything", ... )
);
print $lower_array_object["something"]; //prints "anything"
Class
class CaseInsensitiveArray implements ArrayAccess
{
private $_container = array();
public function __construct( Array $initial_array = array() ) {
$this->_container = array_map( "strtolower", $initial_array );
}
public function offsetSet($offset, $value) {
if( is_string( $offset ) ) $offset = strtolower($offset);
if (is_null($offset)) {
$this->container[] = $value;
} else {
$this->container[$offset] = $value;
}
}
public function offsetExists($offset) {
if( is_string( $offset ) ) $offset = strtolower($offset);
return isset($this->_container[$offset]);
}
public function offsetUnset($offset) {
if( is_string( $offset ) ) $offset = strtolower($offset);
unset($this->container[$offset]);
}
public function offsetGet($offset) {
if( is_string( $offset ) ) $offset = strtolower($offset);
return isset($this->container[$offset])
? $this->container[$offset]
: null;
}
}
You can't do this without either a linear search or altering the original array. The most efficient approach will be to use strtolower on keys when you insert AND when you lookup values.
$myArray[strtolower('SOmeKeyNAme')]=7;
if (isset($myArray[strtolower('SomekeyName')]))
{
}
If it's important to you to preserve the original case of the key, you could store it as a additional value for that key, e.g.
$myArray[strtolower('SOmeKeyNAme')]=array('SOmeKeyNAme', 7);
As you updated the question to suggest this wouldn't be possible for you, how about you create an array providing a mapping between lowercased and case-sensitive versions?
$keys=array_keys($myArray);
$map=array();
foreach($keys as $key)
{
$map[strtolower($key)]=$key;
}
Now you can use this to obtain the case-sensitive key from a lowercased one
$test='somekeyname';
if (isset($map[$test]))
{
$value=$myArray[$map[$test]];
}
This avoids the need to create a full copy of the array with a lower-cased key, which is really the only other way to go about this.
If making a full copy of the array isn't a concern, then you can use array_change_key_case to create a copy with lower cased keys.
$myCopy=array_change_key_case($myArray, CASE_LOWER);
You could loop through the array manually and search for a match.
foreach( $myArray as $key => $value ) {
if( strtolower( $key ) == 'somekeyname' ) {
// match found, $value == $myArray[ 'SOmeKeyNAme' ]
}
}