Как я могу защитить часть массива в php от изменения? - PullRequest
2 голосов
/ 31 июля 2009

У меня есть массив в php, как это:

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

Мне нужно, чтобы этот массив был доступен по сценарию, чтобы разрешить изменения в любом поле, КРОМЕ в поле "config". Есть ли способ защитить массив или часть массива от изменения, как если бы он был объявлен закрытым внутри класса? Я попытался определить его как константу, но его значение изменяется во время выполнения скрипта. Реализация его как класса означала бы, что мне придется перестраивать полное приложение с нуля: S

спасибо!

Ответы [ 3 ]

5 голосов
/ 31 июля 2009

Я не думаю, что вы можете сделать это, используя "чистые" "реальные" массивы.

Один способ добраться до этого может использовать некоторый класс, который реализует ArrayInterface; ваш код будет выглядеть так, как будто он использует массивы ... Но на самом деле он будет использовать объекты с методами доступа, которые могут запретить доступ на запись к некоторым данным, я думаю ...

Это заставит вас изменить пару вещей (создать класс, создать его экземпляр) ; но не все : для доступа по-прежнему будет использоваться синтаксис, похожий на массив.


Нечто подобное может сделать трюк (адаптировано из руководства) :

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

Вы должны создать экземпляр объекта с new, который не очень похож на массив ... Но после этого вы можете использовать его как массив.


И при попытке записать в «заблокированное» свойство, вы можете выдать исключение или что-то в этом роде - кстати, лучше объявить новый класс Exception, например ForbiddenWriteException: он позволит поймать именно эти : -)

2 голосов
/ 31 июля 2009

Вы можете сделать массив закрытым и создать метод для изменения его содержимого, который будет проверять, не пытается ли кто-нибудь перезаписать ключ config.

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

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

Затем, когда вы хотите изменить массив, вы вызываете:

MyClass::setMyArray('foo', 'bar'); // this will work
MyClass::setMyArray('config', 'bar'); // this will be ignored
1 голос
/ 31 июля 2009

Нет, к сожалению, нет способа сделать то, что вы описываете. Переменные не имеют понятия общего или частного, если они не заключены в объект.

Наилучшим решением, к сожалению, является переработка конфигурации в объектный формат. Возможно, вы сможете использовать небольшой объект внутри вашего массива, который содержит частные настройки, что может позволить вам обновить только несколько мест в коде, в зависимости от того, где используется эта часть массива.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...