PHP глобальный в функциях
В чем полезность глобального ключевого слова?
Есть ли причины предпочитать один метод другому?
- Безопасность?
- Спектакль?
- Что-нибудь еще?
Способ 1:
function exempleConcat($str1, $str2)
{
return $str1.$str2;
}
Способ 2:
function exempleConcat()
{
global $str1, $str2;
return $str1.$str2;
}
Когда имеет смысл использовать global
?
Для меня это кажется опасным... но это может быть просто недостаток знаний. Меня интересуют документированные (например, с примером кода, ссылки на документацию...) технические причины.
Заранее спасибо!
премия
Это хороший общий вопрос по теме, я (@Gordon) предлагаю вознаграждение за дополнительные ответы. Согласен ли мой ответ с моим или дает другую точку зрения, не имеет значения. Так как global
тема возникает время от времени, мы могли бы использовать хороший "канонический" ответ для ссылки на.
7 ответов
Глобалы злые
Это верно для global
ключевое слово, а также все остальное, что распространяется от локальной области до глобальной области (статика, синглтоны, реестры, константы). Вы не хотите их использовать. Вызов функции не должен полагаться на что-либо извне, например
function fn()
{
global $foo; // never ever use that
$a = SOME_CONSTANT // do not use that
$b = Foo::SOME_CONSTANT; // do not use that unless self::
$c = $GLOBALS['foo']; // incl. any other superglobal ($_GET, …)
$d = Foo::bar(); // any static call, incl. Singletons and Registries
}
Все это сделает ваш код зависимым от внешнего мира. Это означает, что вы должны знать полное глобальное состояние, в котором находится ваше приложение, прежде чем вы сможете надежно вызвать любой из них. Функция не может существовать без этой среды.
Использование суперглобальных не может быть очевидным недостатком, но если вы вызываете свой код из командной строки, у вас нет $_GET
или же $_POST
, Если ваш код основан на вводе данных, вы ограничиваетесь веб-средой. Просто абстрагируйте запрос в объект и используйте его вместо этого.
В случае связывания жестко закодированных имен классов (статические, константы) ваша функция также не может существовать без доступности этого класса. Это не проблема, когда классы находятся в одном и том же пространстве имен, но когда вы начинаете микширование из разных пространств имен, вы создаете запутанный беспорядок.
Повторное использование серьезно затруднено всем вышеперечисленным. Так же как и юнит-тестирование.
Кроме того, сигнатуры вашей функции лежат, когда вы подключаетесь к глобальной области видимости
function fn()
это лжец, потому что он утверждает, что я могу вызвать эту функцию, ничего не передавая ей. Только когда я смотрю на тело функции, я узнаю, что должен установить среду в определенное состояние.
Если вашей функции требуются аргументы для запуска, сделайте их явными и передайте в:
function fn($arg1, $arg2)
{
// do sth with $arguments
}
ясно из подписи передает то, что требуется назвать. Это не зависит от окружающей среды, чтобы быть в определенном состоянии. Вам не нужно делать
$arg1 = 'foo';
$arg2 = 'bar';
fn();
Это вопрос вставки (глобальное ключевое слово) против вставки (аргументы). Когда вы вставляете / вводите зависимости, функция больше не зависит от внешней стороны. Когда вы делаете fn(1)
вам не нужно иметь переменную, содержащую 1 где-то снаружи. Но когда вы тянете в глобальном $one
внутри функции вы соединяетесь с глобальной областью видимости и ожидаете, что у нее будет переменная, определенная где-то. Функция больше не является независимой.
Еще хуже, когда вы меняете глобальные переменные внутри своей функции, ваш код быстро станет совершенно непонятным, потому что ваши функции повсюду имеют побочные эффекты.
В отсутствие лучшего примера рассмотрим
function fn()
{
global $foo;
echo $foo; // side effect: echo'ing
$foo = 'bar'; // side effect: changing
}
И тогда вы делаете
$foo = 'foo';
fn(); // prints foo
fn(); // prints bar <-- WTF!!
Там нет никакого способа увидеть это $foo
изменился из этих трех строк. Почему вызов одной и той же функции с одинаковыми аргументами внезапно изменит ее вывод или изменит значение в глобальном состоянии? Функция должна делать X для определенного входа Y. Всегда.
Это становится еще более серьезным при использовании ООП, поскольку ООП подразумевает инкапсуляцию и, достигнув глобальной области, вы нарушаете инкапсуляцию. Все эти Singletons и Registries, которые вы видите в рамках, являются запахами кода, которые должны быть удалены в пользу Dependency Injection. Отделите ваш код.
Больше ресурсов:
Глобалы неизбежны.
Это старая дискуссия, но я все же хотел бы добавить некоторые мысли, потому что я скучаю по ним в вышеупомянутых ответах. Эти ответы упрощают то, что глобальное слишком много, и представляют решения, которые вовсе не являются решением проблемы. Проблема заключается в следующем: как правильно обращаться с глобальной переменной и использовать ключевое слово global? Для этого нужно сначала изучить и описать, что такое глобальный.
Взгляните на этот код Zend - и, пожалуйста, поймите, что я не предполагаю, что Zend написан плохо:
class DecoratorPluginManager extends AbstractPluginManager
{
/**
* Default set of decorators
*
* @var array
*/
protected $invokableClasses = array(
'htmlcloud' => 'Zend\Tag\Cloud\Decorator\HtmlCloud',
'htmltag' => 'Zend\Tag\Cloud\Decorator\HtmlTag',
'tag' => 'Zend\Tag\Cloud\Decorator\HtmlTag',
);
Здесь много невидимых зависимостей. Эти константы на самом деле являются классами. Вы также можете увидеть require_once на некоторых страницах этого фреймворка. Require_once является глобальной зависимостью, следовательно, создает внешние зависимости. Это неизбежно для рамок. Как создать класс наподобие DecoratorPluginManager без большого количества внешнего кода, от которого он зависит? Он не может функционировать без множества дополнений. Используя Zend Framework, вы когда-нибудь меняли реализацию интерфейса? Интерфейс на самом деле является глобальным.
Другое глобально используемое приложение - Drupal. Они очень заботятся о правильном дизайне, но, как и любая большая платформа, у них много внешних зависимостей. Посмотрите на глобалы на этой странице:
/**
* @file
* Initiates a browser-based installation of Drupal.
*/
/**
* Root directory of Drupal installation.
*/
define('DRUPAL_ROOT', getcwd());
/**
* Global flag to indicate that site is in installation mode.
*/
define('MAINTENANCE_MODE', 'install');
// Exit early if running an incompatible PHP version to avoid fatal errors.
if (version_compare(PHP_VERSION, '5.2.4') < 0) {
print 'Your PHP installation is too old. Drupal requires at least PHP 5.2.4. See the <a href="http://drupal.org/requirements">system requirements</a> page for more information.';
exit;
}
// Start the installer.
require_once DRUPAL_ROOT . '/includes/install.core.inc';
install_drupal();
Вы когда-нибудь писали перенаправление на страницу входа? Это меняет глобальное значение. (И затем вы не говорите "WTF", что я считаю хорошей реакцией на плохую документацию вашего приложения.) Проблема с глобальными именами заключается не в том, что они являются глобальными, вам нужны они для того, чтобы иметь содержательное приложение. Проблема заключается в сложности всего приложения, которое может сделать его кошмаром. Сессии - глобальные, $_POST - глобальный, DRUPAL_ROOT - глобальный, include / install.core.inc '- неизменяемый глобал. За пределами любой функции существует большой мир, необходимый для того, чтобы эта функция выполняла свою работу.
Ответ Гордона неверен, потому что он переоценивает независимость функции, а вызов функции лжецом упрощает ситуацию. Функции не лгут, и когда вы смотрите на его пример, функция разработана неправильно - его пример - ошибка. (Между прочим, я согласен с этим выводом, что следует отделить код.) Ответ deceze на самом деле не является правильным определением ситуации. Функции всегда функционируют в более широкой области, и его пример слишком упрощен. Мы все согласимся с ним, что эта функция совершенно бесполезна, потому что она возвращает константу. Эта функция в любом случае плохой дизайн. Если вы хотите показать, что практика плохая, приведите соответствующий пример. Переименование переменных в приложении - это не проблема, если у вас есть хорошая IDE (или инструмент). Вопрос заключается в области действия переменной, а не в разнице области действия функции. У функции есть подходящее время для выполнения своей роли в процессе (именно поэтому она создается в первую очередь), и в это время она может влиять на функционирование приложения в целом, следовательно, также работать с глобальными переменными., Ответом xzyfer является утверждение без аргументации. Глобальные переменные также присутствуют в приложении, если у вас есть процедурные функции или дизайн ООП. Следующие два способа изменения значения global по сути одинаковы:
function xzy($var){
global $z;
$z = $var;
}
function setZ($var){
$this->z = $var;
}
В обоих случаях значение $z изменяется в пределах определенной функции. В обоих случаях программирования вы можете внести эти изменения в кучу других мест в коде. Вы можете сказать, что используя global, вы можете вызывать $z где угодно и менять там. Да, ты можешь. А ты? И когда это сделано в неподходящих местах, не должно ли это тогда быть ошибкой?
Боб Фэнджер комментирует xzyfer.
Должен ли кто-то просто использовать что-нибудь, особенно ключевое слово "глобальный"? Нет, но, как и любой тип дизайна, постарайтесь проанализировать, что зависит и что от него зависит. Попытайтесь выяснить, когда это изменяется и как это изменяется. Изменение глобальных значений должно происходить только с теми переменными, которые могут меняться при каждом запросе / ответе. То есть только для тех переменных, которые относятся к функциональному потоку процесса, а не к его технической реализации. Перенаправление URL на страницу входа в систему относится к функциональному потоку процесса, классу реализации, используемому для интерфейса с технической реализацией. Вы можете изменить последний в разных версиях приложения, но не следует менять их при каждом запросе / ответе.
Чтобы лучше понять, когда возникает проблема работы с глобальными и глобальным ключевым словом, а когда нет, я введу следующее предложение, которое приходит от Вима де Би при написании статей о блогах: "Личное да, личное нет". Когда функция изменяет значение глобальной переменной ради своего собственного функционирования, тогда я назову это частным использованием глобальной переменной и ошибкой. Но когда изменение глобальной переменной сделано для правильной обработки приложения в целом, например, перенаправления пользователя на страницу входа в систему, то, по моему мнению, возможно, хороший дизайн, по определению не плохой и, конечно, не анти-модель.
Оглядываясь назад, на ответы Гордона, Десезе и Шзифера: в качестве примеров у всех них есть "личное да" (и ошибки). Вот почему они против использования глобалов. Я бы тоже так сделал. Они, однако, не содержат "личное да, личное нет" - примеры, которые я несколько раз приводил в этом ответе.
Одна большая причина против global
является то, что это означает, что функция зависит от другой области. Это очень быстро запутается.
$str1 = 'foo';
$str2 = 'bar';
$str3 = exampleConcat();
против
$str = exampleConcat('foo', 'bar');
требующий $str1
а также $str2
быть установленным в области вызова для работы функции означает, что вы вводите ненужные зависимости. Вы больше не можете переименовывать эти переменные в этой области, не переименовывая их и в функции, и, следовательно, во всех других областях, в которых вы используете эту функцию. Вскоре это превращается в хаос, когда вы пытаетесь отслеживать имена переменных.
global
это плохая модель даже для включения глобальных вещей, таких как $db
Ресурсы. Придет день, когда вы хотите переименовать $db
но не могу, потому что все ваше приложение зависит от имени.
Ограничение и разделение области видимости переменных важно для написания любого наполовину сложного приложения.
Проще говоря, редко есть причина global
и никогда не хороший в современном коде PHP ИМХО. Особенно, если вы используете PHP 5. И особенно, если вы разрабатываете объектно-ориентированный код.
Глобальные переменные негативно влияют на удобство сопровождения, читаемость и тестируемость кода. Многие использования global
можно и нужно заменить на Dependency Injection или просто передать глобальный объект в качестве параметра.
function getCustomer($db, $id) {
$row = $db->fetchRow('SELECT * FROM customer WHERE id = '.$db->quote($id));
return $row;
}
Не стесняйтесь использовать глобальное ключевое слово внутри функций в PHP. Особенно не принимайте людей, которые диковинно проповедуют / кричат, что глобалы "злы" и еще много чего.
Во-первых, потому что то, что вы используете, полностью зависит от ситуации и проблемы, и нет единого решения / способа что-либо сделать в кодировании. Полностью оставляя в стороне заблуждение неопределимых, субъективных, религиозных прилагательных типа "зло" в уравнении.
Дело в точке:
Wordpress и его экосистема используют глобальные ключевые слова в своих функциях. Будь код ООП или не ООП.
На сегодняшний день WordPress составляет в основном 18,9% Интернета, и на нем работают огромные мегасайты / приложения от бесчисленных гигантов, от Reuters до Sony, NYT и CNN.
И это хорошо.
Использование глобального ключевого слова внутри функций освобождает Wordpress от раздувания MASSIVE, что могло бы произойти, учитывая его огромную экосистему. Представьте, что каждая функция запрашивает / передает любую переменную, которая необходима от другого плагина, ядра и возврата. Добавленный с взаимозависимостями плагина, который закончился бы кошмаром переменных, или кошмаром массивов, переданных как переменные. Ад, чтобы отследить, ад для отладки, ад для развития. Неоправданно большой объем памяти из-за раздувания кода и разрыва переменных тоже. Тяжелее писать тоже.
Могут быть люди, которые приходят и критикуют Wordpress, его экосистему, их практику и то, что происходит в этих частях.
Бессмысленно, так как эта экосистема составляет в значительной степени 20% примерно всего Интернета. Видимо, он работает, он делает свою работу и многое другое. Что означает то же самое для глобального ключевого слова.
Другим хорошим примером является фундаментализм "iframes являются злом". Десять лет назад было ересью использовать фреймы. И тысячи людей проповедовали против них по интернету. Затем идет Facebook, затем идет социальная сеть, теперь iframes везде - от "похожих" ящиков до аутентификации, и вуаля - все заткнутся. Есть те, кто до сих пор не заткнулся - справедливо или неправомерно. Но вы знаете, что жизнь продолжается, несмотря на такие мнения, и даже те, кто проповедовал против фреймов десять лет назад, теперь вынуждены использовать их для интеграции различных социальных приложений в собственные приложения своей организации, не говоря ни слова.
......
Кодер Фундаментализм это что-то очень и очень плохое. Небольшой процент среди нас может быть наделен удобной работой в солидной монолитной компании, которая обладает достаточным влиянием, чтобы выдержать постоянные изменения в информационных технологиях и давление, которое она оказывает в отношении конкуренции, времени, бюджета и других соображений, и поэтому может практиковать фундаментализм и строгое соблюдение воспринимаемого "зла" или "блага". Удобные позиции, напоминающие о старости, даже если оккупанты молоды.
Однако для большинства этот мир - это постоянно меняющийся мир, в котором они должны быть открытыми и практичными. В фундаментализме нет места, оставьте в стороне передовые траншеи информационных технологий, такие как "зло".
Просто используйте все, что лучше всего подходит для решения проблемы, с соответствующими соображениями на ближайшее, среднесрочное и долгосрочное будущее. Не уклоняйтесь от использования какой-либо функции или подхода, потому что он имеет безудержную идеологическую враждебность к нему, среди любого данного подмножества кодеров.
Они не будут делать вашу работу. Ты сможешь. Действуйте согласно вашим обстоятельствам.
Нет смысла создавать функцию concat, используя ключевое слово global.
Он используется для доступа к глобальным переменным, таким как объект базы данных.
Пример:
function getCustomer($id) {
global $db;
$row = $db->fetchRow('SELECT * FROM customer WHERE id = '.$db->quote($id));
return $row;
}
Это может быть использовано как вариация на шаблоне Singleton
Я думаю, что все в значительной степени излагали негативные аспекты глобалов. Поэтому я добавлю положительные стороны, а также инструкции по правильному использованию глобалов:
Основной целью глобалов был обмен информацией между функциями. В те времена, когда не было ничего похожего на класс, PHP-код состоял из множества функций. Иногда вам нужно будет обмениваться информацией между функциями. Как правило, глобальный используется для этого с риском повреждения данных, делая их глобальными.
Теперь, прежде чем какой-то счастливый и счастливый удачливый начнёт комментарий о внедрении зависимостей, я хотел бы спросить вас, как пользователь функции, например,
get_post(1)
знал бы все зависимости функции. Также учтите, что зависимости могут отличаться от
версия к версии и сервер к серверу. Основная проблема с внедрением зависимостей заключается в том, что зависимости должны быть известны заранее. В ситуации, когда это невозможно или нежелательные глобальные переменные были единственным способом достижения этой цели.Благодаря созданию класса, теперь общие функции могут быть легко сгруппированы в класс и обмениваться данными. Благодаря таким реализациям, как Mediators, даже несвязанные объекты могут обмениваться информацией. Это больше не нужно.
Другое использование для глобалов для целей конфигурации. Главным образом в начале сценария, перед загрузкой автозагрузчиков, установлением соединений с базой данных и т. Д.
Во время загрузки ресурсов глобальные параметры могут использоваться для настройки данных (т. Е. Какую базу данных использовать, где расположены библиотечные файлы, URL-адрес сервера и т. Д.). Лучший способ сделать это с помощью
define()
функция, так как эти значения не изменяются часто и могут быть легко помещены в файл конфигурации.Окончательное использование глобальных переменных - хранение общих данных (например, CRLF, IMAGE_DIR, IMAGE_DIR_URL), удобочитаемых флагов состояния (например, ITERATOR_IS_RECURSIVE). Здесь глобальные переменные используются для хранения информации, предназначенной для использования в масштабах всего приложения, что позволяет их изменять и отображать эти изменения в масштабах всего приложения.
Паттерн синглтона стал популярным в php во время php4, когда каждый экземпляр объекта занимал память. Синглтон помог сохранить оперативную память, позволив создать только один экземпляр объекта. До ссылок даже введение зависимости было бы плохой идеей.
Новая реализация php объектов из PHP 5.4+ решает большинство из этих проблем, вы можете безопасно передавать объекты с минимальными затратами. Это больше не нужно.
Другое использование синглетов - это особый случай, когда одновременно должен существовать только один экземпляр объекта, этот экземпляр может существовать до / после выполнения сценария, и этот объект совместно используется различными сценариями / серверами / языками и т. Д. Здесь шаблон синглтона решает Решение довольно хорошо.
Таким образом, в заключение, если вы находитесь в положении 1, 2 или 3, тогда разумно использовать глобальные. Однако в других ситуациях следует использовать метод 1.
Не стесняйтесь обновлять любые другие случаи, когда глобальные переменные должны использоваться.