Каков самый элегантный способ определить глобальный постоянный массив в PHP

Мне было интересно, какой, по вашему мнению, был бы лучший и самый чистый способ определить переменную константного массива, подобно тому, как работает функция define. Я видел много людей, задающих этот вопрос в Google, и до сих пор самым простым решением, которое я придумал, является использование функции PHP serialize внутри оператора define, как это

define ("MY_ARRAY", serialize (array ("key1" => $value1,"key2" => $value2, ..)));

затем, чтобы использовать определенную константу, вы можете сделать что-то вроде этого:

$MY_ARRAY = unserialize (MY_ARRAY)
print_r ($MY_ARRAY);

Не уверен, что функция serialize замедлит работу, если в вашем коде много определений. Что вы думаете?


person techexpert    schedule 09.01.2011    source источник
comment
Для чего вам нужен глобальный var. Возможно, есть лучший подход.   -  person PeeHaa    schedule 09.01.2011
comment
$GLOBALS['MY_ARRAY'] = массив();   -  person dqhendricks    schedule 09.01.2011
comment
PeeHaa, мне нужно, чтобы он был глобальным, если бы я хотел получить доступ к массиву констант из любого класса или функции в том же пространстве имен!   -  person techexpert    schedule 09.01.2011
comment
dqhendricks - ваше решение очень привлекательно, но разве вам не нужно всегда использовать $GLOBALS['MY_ARRAY'] всякий раз, когда вы хотите получить к нему доступ? Кроме того, $GLOBALS также является постоянным? Думаю, нет!   -  person techexpert    schedule 09.01.2011
comment
$GLOBALS — это суперглобальная переменная, доступная в любой части вашего кода, подобно $_POST или $_GET. Хотя вы правы, это не совсем константа. PHP не поддерживает константные массивы.   -  person dqhendricks    schedule 09.01.2011
comment
да, вам придется использовать $GLOBALS['MY_ARRAY'] всякий раз, когда вы хотите получить к нему доступ, но, по крайней мере, вам не нужно десериализовать.   -  person dqhendricks    schedule 09.01.2011


Ответы (2)


Сериализация и особенно десериализация довольно неудобны. (С другой стороны, не совсем понятно, почему язык сценариев не может иметь массивы в качестве констант...)

Но это действительно зависит от модели использования. Обычно вам нужны глобальные определения для хранения настроек конфигурации. И глобальные переменные и константы являются подходящим использованием для этого (несмотря на мем «глобальные зло!! 1!»). Но желательно все закинуть в какой-нибудь объект реестра или массив хотя бы:

class config {
     var $MY_ARRAY = array("key1"=>...);
     var $data_dir = "/tmp/";
} 

Это дает простейший синтаксис доступа с config::$MY_ARRAY. Это не совсем постоянная величина, но ее легко можно подделать. Просто используйте ArrayObject или ArrayAccess и реализуйте его таким образом, чтобы сделать атрибуты доступными только для чтения. (Заставьте offsetSet выдавать ошибку.)

Если вам нужен обходной путь константы глобального массива, тогда другой вариант (я украл эту идею из определить справочную страницу) заключается в использовании функции вместо константы:

function MY_ARRAY() {
     return array("key1" => $value1,);
}

Доступ снова не совсем постоянный, но MY_ARRAY() достаточно короткий. Хотя хороший доступ к массиву с помощью MY_ARRAY()["key1"] невозможен до PHP 5.3; но опять же, это можно подделать, например, с помощью MY_ARRAY("key1").

person mario    schedule 09.01.2011
comment
Марио, что потенциально может пойти не так с сериализацией? Кроме того, ни функция, ни класс не попадут в глобальную область видимости. - person techexpert; 09.01.2011
comment
@techexpert, на самом деле в сериализации нет ничего плохого. Но unserialize(MY_ARRAY) читается довольно долго, и для распаковки всегда нужна временная переменная. Этот вид побеждает цель легкого доступа к константам. Вы также можете определить функцию my_const_array("NAME"), чтобы получить ее из реестра. - person mario; 09.01.2011
comment
Я действительно хотел найти альтернативу оператору определения для массивов, чтобы вы могли передать переменную любой функции в чистом виде, например: call_function(MY_ARRAY) - person techexpert; 09.01.2011
comment
Я бы сказал, что те же 2 исключения, которые я указал на ответ dqhendricks, применяются здесь, но также и ГОЛОСОВАТЬ за аккуратный ответ !!! Благодарю вас! ;) - person techexpert; 09.01.2011
comment
Протестировал, не работает (я что-то упустил?): class MyClass { var $test = array('foo', 'bar'); } эхо MyClass::$test; (пробовали здесь: sandbox.onlinephpfunctions.com/:) - person run_the_race; 26.06.2020

person    schedule
comment
Может ли кто-нибудь переопределить MY_ARRAY с помощью $_POST[MY_ARRAY} или $_GET[MY_ARRAY] и таким образом внедрить свой собственный код? - person techexpert; 09.01.2011
comment
нет, именно поэтому были изобретены суперглобальные массивы. в старые времена люди устанавливали его в конфигурации PHP, чтобы переменные поста становились глобальными переменными, пока не поняли, что это мечта хакеров. чтобы быть уверенным, попробуйте это на своем тестовом сервере и посмотрите, что произойдет. - person dqhendricks; 09.01.2011
comment
$GLOBALS никак не связан с переменными $_POST или $_GET. - person dqhendricks; 09.01.2011
comment
define также делает переменную суперглобальной? - person techexpert; 09.01.2011
comment
ну, это будет связано, если вы находитесь на злом злом хосте, на котором все еще включена функция register_globals. Но в остальном да, они совершенно разные. - person Marc B; 09.01.2011
comment
определить просто делает глобальный. суперглобальные значения никогда не нужно определять в первую очередь. - person dqhendricks; 09.01.2011
comment
Это выглядит чистым и довольно простым в использовании, за исключением того, что: а) вам нужно использовать $GLOBALS каждый раз, когда вы хотите передать его функции, например, int call_function($GLOBALS['MY_ARRAY']) и б) это не совсем константа, но в противном случае ГОЛОСОВАНИЕ за действительно аккуратное решение! Благодарю вас! :) - person techexpert; 09.01.2011
comment
вам НЕ нужно передавать его функциям... массив $GLOBALS доступен в КАЖДОЙ части вашего кода ВСЕГДА. - person dqhendricks; 09.01.2011
comment
Ну, это зависит... У меня есть класс, который генерирует некоторые объекты на основе значений, указанных в постоянном массиве (val1, val2, val3), и у меня есть набор этих массивов, каждый из которых указывает предопределенную конфигурацию объекта, поэтому Мне пришлось бы передать каждый из этих массивов конструктору класса, чтобы сгенерировать несколько версий этих объектов на основе значений, указанных в массивах, максимально чистым способом. В этом случае я должен указать, на основе какого массива я хочу построить классы - person techexpert; 09.01.2011
comment
.. передав его функции-конструктору, например, foo(ARRAY1), foo(ARRAY2), где foo — конструктор класса - person techexpert; 09.01.2011
comment
звучит так, будто вы должны либо создавать подклассы, расширяющие ваш класс, либо вы можете просто передать ключевую строку $GLOBALS, а не весь массив, содержащийся в этом ключе. - person dqhendricks; 09.01.2011
comment
Это хорошее предложение! Проведя некоторое тестирование с помощью $GLOBALS и define, я решил использовать define для своего приложения, потому что это на самом деле выдаст ошибку, если вы попытаетесь чтобы переопределить переменную после того, как она уже была установлена. Но мне пришлось пожертвовать частью скорости приложения в процессе. Мне тоже очень нравится ваше решение. Спасибо тебе за помощь! - person techexpert; 09.01.2011
comment
Кстати, я создаю подклассы, но для того, чтобы я мог ссылаться на них, я использую define(OBJECT_ONE, serialize(array(class1 => obj1_class1, class2 => obj1_class2, class3 = obj1_class3))); Затем мой базовый класс генерирует экземпляры своих дочерних элементов на лету, но для этого я должен передать определенную переменную методу addChildren(OBJECT_ONE), а затем addChildren(OBJECT_TWO ) и т. д. Каждый объект имеет имена классов, отличные друг от друга, и базовый класс не знает, как обращаться к ним иначе, отсюда и define(). Оно работает! Надеюсь, я не слишком вас запутал :) - person techexpert; 09.01.2011