views:

66

answers:

3

I have an array in php like this:

$myArray = array('name'=>'juank', 'age'=>26, 'config'=>array('usertype'=>'admin','etc'=>'bla bla'));

I need this array to be accesible along the script to allow changes in any field EXCEPT in the "config" field. Is there a way to protect an array or part of an array from being modified as if it where declared private inside a class? I tried defining it as a constant but it's value changes during script execution. Implementing it as a class would mean I'd have to rebuild the complete application from scratch :S

thanks!

+1  A: 

No, unfortunately there isn't a way to do what you're describing. Variables don't have any concept of public or private unless they are encapsulated within an object.

Your best solution is unfortunately to re-work the configuration into an object format. You might be able to use a small object inside your array that contains the private settings, which might allow you to only have to update a few places in your code, depending where that portion of the array is used.

zombat
+2  A: 

You could make the array private and create a method to modify its contents that will check if someone doesn't try to overwrite the config key.

<?php
    class MyClass {
        private static $myArray = array(
            'config' => array(...),
            'name' => ...,
            ...
        );

        public static function setMyArray($key, $value) {
            if ($key != 'config') {
                $this::myArray[$key] = $value;
            }
        }
    }

Then when you want to modify the array you call:

MyClass::setMyArray('foo', 'bar'); // this will work
MyClass::setMyArray('config', 'bar'); // this will be ignored
RaYell
Isn't this exactly the situation that the poster is trying to avoid? Having to re-tool his array into a class?
zombat
I'm afraid that's the only way, and I think it can be worth the effort since it's like 5 lines of code.
RaYell
+5  A: 

I do not think you can do this using "pure" "real" arrays.

One way to get to this might be using some class that implements ArrayInterface ; you code would look like it's using arrays... But it would actually be using objects, with accessor methods that could forbid write-access to some data, I guess...

It would have you change a couple of things (creating a class, instanciating it) ; but not everything : access would still be using an array-like syntax.


Something like this might do the trick (adapted from the manual) :

class obj implements arrayaccess {
    private $container = array();
    public function __construct() {
        $this->container = array(
            "one"   => 1,
            "two"   => 2,
            "three" => 3,
        );
    }
    public function offsetSet($offset, $value) {
        if ($offset == 'one') {
            throw new Exception('not allowed : ' . $offset);
        }
        $this->container[$offset] = $value;
    }
    public function offsetExists($offset) {
        return isset($this->container[$offset]);
    }
    public function offsetUnset($offset) {
        unset($this->container[$offset]);
    }
    public function offsetGet($offset) {
        return isset($this->container[$offset]) ? $this->container[$offset] : null;
    }
}


$a = new obj();

$a['two'] = 'glop'; // OK
var_dump($a['two']); // string 'glop' (length=4)

$a['one'] = 'boum'; // Exception: not allowed : one

You have to instanciate an object with new, which is not very array-like... But, after that, you can use it as an array.


And when trying to write to an "locked" property, you can throw an Exception, or something like that -- btw, declaring a new Exception class, like ForbiddenWriteException, would be better : would allow to catch those specifically :-)

Pascal MARTIN
+1 this is how I would do it.
Peter Bailey
+1 very clever! I learned something too. :)
zombat
I was trying to avoid using a class due to the restructuring of the app but given your solution Pascal,I see now a huge potential benefit in using this class. thank you very much!
Juank
You're welcome :-) Have fun with that ;-)
Pascal MARTIN