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

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

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

Является ли эта плохая практика?

Ответ 1

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

Часто (всегда?) вы можете вызывать функции-члены в методах типа preg_replace_callback() следующим образом:

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

Подробнее см. обратные вызовы.

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

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

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

Ответ 2

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

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

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

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

Ответ 3

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

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

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

Ответ 4

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

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

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

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

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

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

Ответ 5

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

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

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

Ваш первый вопрос здесь очевиден.

Откуда $bob?

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

Как мы избегаем Globals?

Лучший способ избежать глобалов - это философия, называемая Injection of Dependency. Здесь мы передаем необходимые нам инструменты в функцию или класс.

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

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

Ответ 6

Как

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['PREFIX-MY-GLOBAL']['context-something'] = 'Transport me ... ';
$GLOBALS['PREFIX-MY-GLOBAL']['context-something-else']['numbers'][] = 'Transport me ... ';

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