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

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

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

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

Способ 1:

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

Способ 2:

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

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

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

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


Bounty

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

Ответ 1

Глобалы злы

Это справедливо для ключевого слова 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. Всегда.

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

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

Ответ 2

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

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

против.

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

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

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

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

Ответ 3

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

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

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

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

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

Ответ 4

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

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

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

Ответ 5

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

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

Пример:

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

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

И все хорошо.

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

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

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

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

......

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

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

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

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

Ответ 6

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

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

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

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

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

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

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

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

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

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

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

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

Ответ 7

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

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

Пример:

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

Его можно использовать как вариацию Singleton pattern