PHP глобальный в функциях - PullRequest
97 голосов
/ 02 марта 2011

Что такое глобальное ключевое слово ?

Есть ли причины предпочитать один метод другому?

  • Безопасность?
  • Производительность?
  • Что-нибудь еще?

Метод 1:

function exempleConcat($str1, $str2)
{
  return $str1.$str2;
}

Метод 2:

function exempleConcat()
{
  global $str1, $str2;
  return $str1.$str2;
}

Когда это происходитсмысл использовать global?

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

Заранее спасибо!


Bounty

Это хороший общий вопрос по теме, я (@Gordon) предлагаю вознаграждение за дополнительные ответы.Согласен ли мой ответ с моим или дает другую точку зрения, не имеет значения.Так как тема global возникает время от времени, мы можем использовать хороший «канонический» ответ для ссылки на

.

Ответы [ 7 ]

154 голосов
/ 02 марта 2011

Глобалы злые

Это верно для ключевого слова 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. Развяжите ваш код.

Дополнительные ресурсы:

35 голосов
/ 02 марта 2011

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

$str1 = 'foo';
$str2 = 'bar';
$str3 = exampleConcat();

против

$str = exampleConcat('foo', 'bar');

Требование настройки $str1 и $str2 в области вызова для работы функции означает, что вы вводите ненужные зависимости. Вы больше не можете переименовывать эти переменные в этой области, не переименовывая их и в функции, и, следовательно, во всех других областях, в которых вы используете эту функцию. Вскоре это превращается в хаос, когда вы пытаетесь отслеживать имена переменных.

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

Ограничение и разделение области видимости переменных необходимо для написания любого наполовину сложного приложения.

34 голосов
/ 04 февраля 2013

Глобалы неизбежны.

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

Ответ Гордона неверен, потому что он переоценивает независимость функции, а вызов функции лжецом упрощает ситуацию. Функции не лгут, и когда вы смотрите на его пример, функция спроектирована неправильно - его пример - ошибка. (Кстати, я согласен с этим выводом, что нужно отделить код.) Ответ децезе не совсем правильное определение ситуации. Функции всегда функционируют в более широкой области, и его пример слишком упрощен. Мы все согласимся с ним, что эта функция совершенно бесполезна, потому что она возвращает константу. Эта функция в любом случае плохой дизайн. Если вы хотите показать, что практика плохая, приведите соответствующий пример. Переименование переменных в приложении - это не проблема, если у вас есть хорошая IDE (или инструмент). Вопрос заключается в области действия переменной, а не в разнице области действия функции. У функции есть подходящее время для выполнения своей роли в процессе (именно поэтому она создается в первую очередь), и в это время она может влиять на функционирование приложения в целом, следовательно, также работать с глобальными переменными. , Ответом xzyfer является утверждение без аргументации. Глобальные переменные также присутствуют в приложении, если у вас есть процедурные функции или дизайн ООП. Следующие два способа изменения значения глобала по сути одинаковы:

function xzy($var){
 global $z;
 $z = $var;
}

function setZ($var){
 $this->z = $var;
}

В обоих случаях значение $ z изменяется в конкретной функции. В обоих случаях программирования вы можете внести эти изменения в кучу других мест в коде. Вы можете сказать, что используя global, вы можете вызывать $ z где угодно и менять там. Да, ты можешь. А ты? И когда это сделано в неподходящих местах, разве это не должно быть названо ошибкой?

Боб Фэнджер комментирует xzyfer.

Должен ли кто-нибудь тогда просто что-нибудь использовать, особенно ключевое слово "global"? Нет, но, как и любой тип дизайна, попробуйте проанализировать, что зависит и что от него зависит. Попытайтесь выяснить, когда это изменяется и как это изменяется. Изменение глобальных значений должно происходить только с теми переменными, которые могут меняться при каждом запросе / ответе. То есть только к тем переменным, которые относятся к функциональному потоку процесса, а не к его технической реализации. Перенаправление URL на страницу входа в систему относится к функциональному потоку процесса, классу реализации, используемому для интерфейса с технической реализацией. Вы можете изменить последнее в разных версиях приложения, но не следует менять их при каждом запросе / ответе.

Чтобы лучше понять, когда возникает проблема работы с глобальными и ключевым словом global, а когда нет, я введу следующее предложение, которое приходит от Wim de Bie, когда пишет о блогах: «Личное да, личное нет». Когда функция изменяет значение глобальной переменной ради своего собственного функционирования, я назову это частным использованием глобальной переменной и ошибкой. Но когда изменение глобальной переменной сделано для правильной обработки приложения в целом, например, перенаправления пользователя на страницу входа в систему, то это, по моему мнению, возможно хороший дизайн, не по определению плохой и, конечно, не анти-модель.

В ретроспективе к ответам Гордона, Десезе и Хзифера: у них у всех есть «личное да» (и ошибки) в качестве примеров. Вот почему они против использования глобалов. Я бы тоже так сделал. Они, однако, не содержат «личное да, личное нет» - примеры, которые я несколько раз приводил в этом ответе.

14 голосов
/ 02 марта 2011

Проще говоря, редко встречается причина для global и никогда не бывает хорошей причины в современном PHP-коде ИМХО. Особенно если вы используете PHP 5. И особенно если вы разрабатываете объектно-ориентированный код.

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

function getCustomer($db, $id) {
    $row = $db->fetchRow('SELECT * FROM customer WHERE id = '.$db->quote($id));
    return $row;
}
8 голосов
/ 23 августа 2014

Не стесняйтесь использовать глобальные ключевые слова внутри функций в PHP. Особенно не принимайте людей, которые диковинно проповедуют / кричат ​​о том, что глобалы «злы» и еще много чего.

Во-первых, то, что вы используете, полностью зависит от ситуации и проблемы, и НЕТ единственного решения / способа что-либо сделать в кодировании. Полностью оставляя в стороне заблуждение неопределенных, субъективных, религиозных прилагательных типа «зло» в уравнении.

Показательный пример:

Wordpress и его экосистема используют глобальные ключевые слова в своих функциях. Будь код ООП или не ООП.

А на данный момент Wordpress в основном составляет 18,9% Интернета, и на нем работают огромные мегасайты / приложения от бесчисленных гигантов, от Reuters до Sony, NYT и CNN.

И это хорошо.

Использование глобального ключевого слова внутри функций освобождает Wordpress от раздувания MASSIVE, что могло бы произойти, учитывая его огромную экосистему. Представьте, что каждая функция запрашивает / передает любую переменную, которая необходима от другого плагина, ядра и возврата. Добавленный с взаимозависимостями плагина, который закончился бы кошмаром переменных, или кошмаром массивов, переданных как переменные. Ад, чтобы отслеживать, ад для отладки, ад, чтобы развиваться. Неоправданно большой объем памяти из-за раздувания кода и разрыва переменных тоже. Тяжелее писать тоже.

Могут быть люди, которые приходят и критикуют Wordpress, его экосистему, их практику и то, что происходит в этих частях.

Бессмысленно, так как эта экосистема составляет почти 20% примерно всего Интернета. Видимо, он работает, он делает свою работу и многое другое. Что означает то же самое для глобального ключевого слова.

Другим хорошим примером является фундаментализм "iframes is evil". Десять лет назад использование айфреймов было ересью. И тысячи людей проповедовали против них по интернету. Затем идет Facebook, затем идет социальная сеть, теперь iframes везде - от «похожих» ящиков до аутентификации, и вуаля - все заткнутся. Есть те, кто до сих пор не заткнулся - справедливо или неправомерно. Но вы знаете, что жизнь продолжается, несмотря на такие мнения, и даже те, кто проповедовал против фреймов десять лет назад, теперь вынуждены использовать их для интеграции различных социальных приложений в собственные приложения своей организации, не говоря ни слова.

......

Кодер Фундаментализм - это что-то очень, очень плохое. Небольшой процент среди нас может быть наделен удобной работой в солидной монолитной компании, у которой достаточно влияния, чтобы выдержать постоянные изменения в информационных технологиях и давление, которое она оказывает в отношении конкуренции, времени, бюджета и других соображений, и поэтому может практиковать фундаментализм и строгое соблюдение воспринимаемого «зла» или «блага». Это удобные позиции, напоминающие о старости, даже если оккупанты молоды.

Для большинства, однако, i.t. Мир - это постоянно меняющийся мир, в котором они должны быть открытыми и практичными. В фундаментализме нет места, оставьте в стороне передовые траншеи информационных технологий, такие как «зло».

Просто используйте все, что лучше всего подходит для этой проблемы, С УЛУЧШЕНИЕМ, с соответствующими соображениями на ближайшее, среднесрочное и долгосрочное будущее. Не уклоняйтесь от использования какой-либо функции или подхода, потому что он имеет безудержную идеологическую враждебность к нему, среди любого данного подмножества кодеров.

Они не будут выполнять вашу работу. Ты сможешь. Действуйте в соответствии с вашими обстоятельствами.

6 голосов
/ 06 февраля 2014

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

  1. Основной целью глобалов был обмен информацией между функциями. назад, когда не было ничего похожего на класс, код php состоял из множества функций. Иногда вам нужно будет обмениваться информацией между функциями. Обычно глобальный был использован для Делайте это с риском повреждения данных, делая их глобальными.

    Теперь, перед тем, как какой-нибудь счастливый счастливчик начинает комментировать про внедрение зависимостей, я хотел бы спросить вас, как бы узнал пользователь такой функции, как пример get_post(1) все зависимости функции. Также учтите, что зависимости могут отличаться от
    версия к версии и сервер к серверу. Основная проблема с внедрением зависимости Это зависимости должны быть известны заранее. В ситуации, когда это невозможно или нежелательные глобальные переменные были единственным способом достижения этой цели.

    Благодаря созданию класса, теперь общие функции могут быть легко сгруппированы в класс и обмениваться данными. Благодаря таким реализациям, как Mediators, даже несвязанные объекты могут делиться Информация. В этом больше нет необходимости.

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

    Во время загрузки ресурсов глобальные параметры могут использоваться для настройки данных (т. Е. Какие база данных, чтобы использовать, где находятся файлы библиотеки, URL-адрес сервера и т. д.). Лучшее способ сделать это с помощью функции define(), так как эти значения не будут часто меняться и может быть легко помещен в файл конфигурации.

  3. Окончательное использование глобалов - хранение общих данных (например, CRLF, IMAGE_DIR, IMAGE_DIR_URL), удобочитаемые флаги состояния (т.е. ITERATOR_IS_RECURSIVE). Здесь глобалы используются для хранения информация, которая предназначена для использования во всем приложении, что позволяет их изменять и эти изменения отображаются в приложении.

  4. Шаблон синглтона стал популярным в php во время php4, когда каждый экземпляр объекта занял память. Синглтон помог спасти оперативную память, позволив только один экземпляр объект, который будет создан. До ссылок даже зависимость от инъекций была бы плохой идея.

    Новая реализация php объектов из PHP 5.4+ решает большинство из этих проблем Вы можете безопасно передавать объекты практически без штрафа. Это больше не необходимо.

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

Таким образом, в заключение, если вы находитесь в позиции 1, 2 или 3, тогда разумно было бы использовать глобал. Однако в других ситуациях следует использовать метод 1.

Не стесняйтесь обновлять любые другие случаи использования глобалов.

5 голосов
/ 02 марта 2011

Нет смысла создавать функцию concat, используя ключевое слово global.

Используется для доступа к глобальным переменным, таким как объект базы данных.

Пример:

function getCustomer($id) {
  global $db;
  $row = $db->fetchRow('SELECT * FROM customer WHERE id = '.$db->quote($id));
  return $row;
}

Может использоваться как вариант синглтон-паттерна

...