Являются ли глобальные переменные в PHP плохой практикой? Если да, то почему?

function foo () { global $var; // rest of code } 

В моих небольших проектах PHP я обычно хожу процедурно. Обычно у меня есть переменная, содержащая конфигурацию системы, и когда я не могу получить доступ к этой переменной в функции, я делаю global $var; ,

Это плохая практика?

Когда люди говорят о глобальных переменных на других языках, это означает нечто иное, чем то, что он делает в PHP. Это потому, что переменные на самом деле не являются глобальными в PHP. Объем типичной PHP-программы – это один HTTP-запрос. Переменные сеанса на самом деле имеют более широкий охват, чем «глобальные» переменные PHP, поскольку они обычно охватывают многие HTTP-запросы.

Часто (всегда?) Вы можете вызвать функции-члены в таких методах, как preg_replace_callback() как это:

 preg_replace_callback('!pattern!', array($obj, 'method'), $str); 

См. Обратные вызовы .

Дело в том, что объекты были закреплены на PHP и в какой-то степени приводят к некоторой неловкости.

Не относитесь к себе чрезмерно с применением стандартов или конструкций с разных языков на PHP. Еще одна распространенная ошибка заключается в том, чтобы превратить PHP в чистый язык ООП, вставив объектные модели поверх всего.

Как и все остальное, используйте «глобальные» переменные, процедурный код, конкретную структуру и ООП, потому что это имеет смысл, решает проблему, уменьшает объем кода, который вам нужно написать, или делает его более удобным и понятным, а не потому, что вы думаете вам следует.

Глобальные переменные, если они не используются тщательно, могут затруднить поиск проблем. Допустим, вы запросите PHP-скрипт, и вы получите предупреждение о том, что вы пытаетесь получить доступ к индексу массива, который не существует в какой-либо функции.

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

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

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

Я согласен с cletus. я бы добавил две вещи:

  1. используйте префикс, чтобы сразу определить его как глобальный (например, $ g_)
  2. объявите их в одном месте, не посыпайте их вокруг кода.

с наилучшими пожеланиями, дон

Кто может возражать против опыта, степени колледжа и разработки программного обеспечения? Не я. Я бы сказал только, что при разработке объектно-ориентированных одностраничных PHP-приложений я получаю больше удовольствия, когда знаю, что я могу построить все с нуля, не беспокоясь о столкновениях пространства имен. Строительство с нуля – это то, что многие люди больше не делают. У них есть работа, крайний срок, бонус или репутация, о которой нужно заботиться. Эти типы, как правило, используют так много заранее построенного кода с высокими ставками, что они не могут рисковать глобальными переменными вообще.

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

Если это означает использование нескольких переменных (<10) в глобальном пространстве имен, которые будут использоваться только в глобальной области программы, пусть будет так. Да, да, MVC, инъекция зависимости, внешний код, бла, бла, бла, бла. Но если вы содержали 99,99% вашего кода в пространствах имен и классах, а внешний код изолирован, мир не закончится (повторюсь, мир не закончится), если вы используете глобальную переменную.

Вообще, я бы не сказал, что использование глобальных переменных – это плохая практика . Я бы сказал, что использование глобальных переменных (флагов и т. Д.) За пределами глобальной области программы задает проблемы и (в конечном счете) не рекомендуется, потому что вы можете легко потерять их состояние. Кроме того, я бы сказал, что чем больше вы узнаете, тем меньше зависит от глобальных переменных, потому что вы испытаете «радость» отслеживания ошибок, связанных с их использованием. Это само по себе побудит вас найти другой способ решить ту же проблему. Кстати, это, как правило, подталкивает людей PHP к тому, чтобы научиться использовать пространства имен и классы (статические члены и т. Д.).

Область информатики обширна. Если мы отпугиваем всех от чего-то сделать, потому что мы плохо маркируем его, то они теряют удовольствие от по-настоящему понимания рассуждений позади метки.

Используйте глобальные переменные, если нужно, но затем посмотрите, сможете ли вы решить проблему без них. Коллизии, тестирование и отладка означают больше, когда вы глубоко понимаете истинную природу проблемы, а не просто описание проблемы.

Отправлено из завершенной бета-версии документации SO

Мы можем проиллюстрировать эту проблему следующим псевдокодом

 function foo() { global $bob; $bob->doSomething(); } 

Ваш первый вопрос здесь является очевидным

Откуда взялся $bob ?

Вы растеряны? Хорошо. Вы только что узнали, почему глобальные люди запутывают и считают плохой практикой. Если бы это была настоящая программа, ваша следующая забава заключалась в том, чтобы отслеживать все экземпляры $bob и надеяться, что вы найдете правильный (это становится хуже, если $bob используется везде). Хуже того, если кто-то еще идет и определяет $bob (или вы забыли и повторно использовали эту переменную), ваш код может сломаться (в приведенном выше примере кода наличие неправильного объекта или вообще никакого объекта приведет к фатальной ошибке). Поскольку практически все PHP-программы используют код типа include('file.php'); ваша работа, поддерживающая такой код, становится экспоненциально сложнее, чем больше файлов вы добавляете.

Как нам избежать глобалов?

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

 function foo(\Bar $bob) { $bob->doSomething(); } 

Это намного легче понять и поддерживать. Невозможно угадать, где был установлен $bob , потому что вызывающий отвечает за то, что он знает, что (мы передаем нам то, что нам нужно знать). Еще лучше, мы можем использовать объявления типа, чтобы ограничить передаваемое. Таким образом, мы знаем, что $bob является либо экземпляром класса Bar , либо экземпляром дочернего элемента Bar , что означает, что мы знаем, что можем использовать методы этого класса. В сочетании со стандартным автозагрузчиком (доступным начиная с PHP 5.3) мы можем теперь отслеживать, где определен Bar . PHP 7.0 или более поздняя версия включает расширенные объявления типов, где вы также можете использовать скалярные типы (например, int или string ).

В виде:

 global $my_global; $my_global = 'Transport me between functions'; Equals $GLOBALS['my_global'] 

это плохая практика (например, WordPress $pagenow ) … hmmm

Указать это:

 $my-global = 'Transport me between functions'; 

это ошибка PHP Но:

 $GLOBALS['my-global'] = 'Transport me between functions'; 

НЕ является ошибкой, hypens не будет сталкиваться с «общими» объявленными пользователем переменными, например $pagenow . И использование UPPERCASE указывает на суперглобал в использовании, легко определить в коде или отслеживать с помощью поиска в файлах

Я использую дефисы, если Im lazy для создания классов всего для одного решения, например:

 $GLOBALS['PREFIX-MY-GLOBAL'] = 'Transport me ... '; 

Но в случаях более широкого использования я использую ONE globals как массив:

 $GLOBALS['PREFIX-MY-GLOBAL']['context-something'] = 'Transport me ... '; $GLOBALS['PREFIX-MY-GLOBAL']['context-something-else']['numbers'][] = 'Transport me ... '; 

Последнее для меня, хорошая практика для целей «cola light» или использования, вместо того, чтобы беспорядок с одноэлементными классами каждый раз «кэшировать» некоторые данные. Пожалуйста, сделайте комментарий, если Im неправильно или отсутствует что-то глупое здесь …