Глобальные функции PHP

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

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

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

Способ 1:

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

Способ 2:

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

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

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

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


премия

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

    Глобалы – злые

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

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

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

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

     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. Всегда.

    Это становится еще более серьезным при использовании ООП, потому что ООП – это инкапсуляция, и, обращаясь к глобальному охвату, вы нарушаете инкапсуляцию. Все эти синглтоны и реестры, которые вы видите в рамках, являются запахами кода, которые следует удалить в пользу Injection Dependency. Развяжите свой код.

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

    • http://c2.com/cgi/wiki?GlobalVariablesAreBad
    • Как протестировать шаблон реестра или singleton hard в PHP?
    • Недостаток: хрупкое глобальное государство и синглтоны
    • static считается вредным
    • Почему Singletons не используют PHP
    • SOLID (объектно-ориентированный дизайн)

    Одна большая причина против 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 – глобальный, include / install.core.inc – немодифицируемый глобальный. Существует большой мир вне любой функции, необходимой для того, чтобы эта функция выполняла свою работу.

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

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

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

    Bob Fanger комментирует xzyfer.

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

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

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

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

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

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

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

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

    ……

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    Пример:

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

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