PHP global в функциях

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

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

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

Способ 1:

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

Способ 2:

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

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

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

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


награда

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

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

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

повторное использование сильно затруднено всем вышеперечисленным. как и модульное тестирование.

кроме того, ваши сигнатуры функций лежат, когда вы соединяетесь с глобальной областью

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

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

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

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

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

Боб Фангер комментирует 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. Особенно не берите людей, которые диковинно проповедуют / кричат, как глобалы "злые" и тому подобное.

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

Case in point :

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

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

и он делает это хорошо.

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

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

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

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

......

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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


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

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

пример:

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

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