Глобальные переменные в PHP считаются плохой практикой? Если так, то почему? - PullRequest
84 голосов
/ 13 октября 2009
function foo () {
    global $var;
    // rest of code
}

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

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

Ответы [ 6 ]

97 голосов
/ 13 октября 2009

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

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

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

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

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

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

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

27 голосов
/ 13 октября 2009

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

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

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

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

16 голосов
/ 13 октября 2009

Я согласен с Клетусом. я бы добавил две вещи:

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

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

5 голосов
/ 10 января 2017

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

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

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

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

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

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

0 голосов
/ 17 октября 2017

Как:

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

это плохая практика (как Wordpress $pagenow) ... хммм

Конкордер это:

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

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

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

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

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

$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", вместо того, чтобы загромождать одноэлементными классами каждый раз для "кэширования" некоторых данных. Пожалуйста, оставьте комментарий, если я ошибаюсь или упускаю что-то глупое здесь ...

0 голосов
/ 24 августа 2017

Перемещено из окончательной документации SO Бета

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

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

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

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

Вы в замешательстве? Хорошо. Вы только что узнали, почему глобалы сбивают с толку и считают плохой практикой. Если бы это была настоящая программа, ваша следующая забавная штука - отследить все экземпляры $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).

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