PHP global в функциях


какова полезность глобальные ключевое слово?

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

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

Способ 1:

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

Способ 2:

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

когда имеет смысл использовать global?

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

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


награда

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

7 95

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();

это вопрос втягивания (глобальное ключевое слово) против нажатия (аргументы). Когда вы нажимаете в зависимостях / inject функция больше не зависит от внешней среды. Когда вы делаете 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. всегда.

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

Больше Ресурсов:

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

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

и

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

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

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

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

глобальные неизбежны.

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

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

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

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

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

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

Боб Фангер комментирует xzyfer.

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

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

оглядываясь назад на ответы Гордона, deceze и xzyfer: все они имеют "личное да" (и ошибки) в качестве примеров. Именно поэтому они выступают против использования глобальных переменных. Я бы тоже. Они, однако, не приходят с "личным да, частным нет" -примеры, как я сделал в этом ответе несколько раз.

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

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

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 от массивного раздувания, которое произойдет, учитывая его огромную экосистему. Представьте себе каждую функцию задавал / передавал любую переменную, которая необходима из другого плагина, ядра и возврата. Добавлено с взаимозависимостями плагинов, которые закончились бы кошмаром переменных или кошмаром массивов, переданных как переменные. Ад для отслеживания, ад для отладки, ад для разработки. Бессмысленно массивный объем памяти из-за раздувания кода и переменной раздувания тоже. Труднее писать.

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

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

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

......

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

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

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

Они не будут делать свою работу. Вы будете. Действуйте в соответствии со своими обстоятельствами.

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

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

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

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

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

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

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

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

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

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

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

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

нет смысла создавать функцию concat с использованием глобального ключевого слова.

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

пример:

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

Он может быть использован в качестве вариации Синглтон шаблон