Доступ к глобальной переменной в функции PHP


84

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

<?php
    $data = 'My data';

    function menugen() {
        echo "[" . $data . "]";
    }

    menugen();
?>

Выход есть [].


3
Не относитесь к этому как к глобальному, передайте его функции как аргумент
Марк Бейкер

2
Где в инструкции такое сказано?
deceze


Посмотрите второй пример на этой странице: php.net/manual/en/language.variables.scope.php
Амин Голибейджан

afaik мы можем получить доступ, используя $ GLOBALS ['varname'], где индекс "varname" - это $ varname вне функции. Фактически, мы можем использовать print_r ($ GLOBALS) для просмотра всех глобальных переменных.
Ахмад

Ответы:


165

Это не работает, потому что вам нужно объявить, к каким глобальным переменным вы будете обращаться:

$data = 'My data';

function menugen() {
    global $data; // <-- Add this line

    echo "[" . $data . "]";
}

menugen();

В противном случае вы можете получить к нему доступ как $GLOBALS['data']. См. Область действия переменной .

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


Спасибо, Вы правы, но они не использовали эту строчку во втором примере руководства: php.net/manual/en/language.variables.scope.php
Амин Голибейджан

6
Фактически, этот второй пример был здесь, чтобы показать читателям, чего не следует делать:This script will not produce any output because the echo statement refers to a local version of the $a variable, and it has not been assigned a value within this scope.
Маттео Тассинари,

2
Черт! Мне пришлось войти в систему, чтобы проголосовать за этот ответ, просто потому, что я жутко забыл об области видимости переменных php.
Милче Патерн

20

Вы можете сделать одно из следующего:

<?php
    $data = 'My data';

    function menugen() {
        global $data;
        echo "[" . $data . "]";
    }

    menugen();

Или же

<?php
    $data = 'My data';

    function menugen() {
        echo "[" . $GLOBALS['data'] . "]";
    }

    menugen();

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


13

Это вопрос объема. Короче говоря, следует избегать глобальных переменных, поэтому :

Вам либо нужно передать его как параметр:

$data = 'My data';

function menugen($data)
{
    echo $data;
}

Или получите его в классе и получите к нему доступ

class MyClass
{
    private $data = "";

    function menugen()
    {
        echo this->data;
    }

}

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


и другой способ - использовать ключевое слово global (конечно, это не лучший способ).
Jocelyn

1
«Следует» не отвечает на вопрос, и это может быть не лучший подход для каждого случая. Для простых скриптов изменение параметров и добавление классов неудобно. Как и в случае с JavaScript, в PHP не все должно быть объектно-ориентированным и располагаться в пространстве имен до wazoo.
Beejor

@Beejor Учитывая, что OP имеет функцию, называемую, menugen()это означает, что будет больше, чем просто создание меню. Например, как насчет расширения этого меню, чтобы добавить больше элементов из другого источника, как насчет выбора текущей выбранной страницы, которая находится в меню. Наличие случайных глобальных переменных и логики повсюду требует дизайна ООП. Тот факт, что PHP / JS не нуждается в структурировании, является одной из основных причин, по которой вы обнаруживаете много беспорядочного неуклюжего кода. Это может быть сделано очень хорошо, но позволяет людям не думать о ремонтопригодности в будущем.
webnoob

ps голосование вниз ответ тоже немного не в тему. Ответ действительно предлагает решение проблемы OP, просто потому, что он вам не нравится, не делает его неправильным.
webnoob

1
@Beejor - Проблема с этим аргументом в том, что люди могут подумать, что им нужна глобальная переменная, потому что они не знают ничего лучшего и не будут знать ничего лучше, если им не скажут.
webnoob

11

Другой способ сделать это:

<?php

$data = 'My data';

$menugen = function() use ($data) {

    echo "[".$data."]";
};

$menugen();

ОБНОВЛЕНИЕ 2020-01-13: по запросу Питера Мортенсена

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

В этом примере закрытие может получить доступ $data потому что оно было объявлено в useпредложении.


Это было единственное рабочее решение в моем случае, когда у меня была функция, определенная как переменная внутри другой функции. Global там не работал.
Kar.ma 04

Объяснение было бы в порядке. Например, что делает эта штука с «употреблением»? В каких версиях PHP поддерживается эта "полезная" штука? (Пожалуйста, ответьте, отредактировав свой ответ , а не здесь, в комментариях (при необходимости). Заранее спасибо.)
Питер Мортенсен

Не знаю, почему одобренный ответ не показывает никаких результатов на странице плагина администратора Wordpress, но этот ответ работает хорошо.
Наймур Хасан

3

На протяжении многих лет я всегда использовал такой формат:

<?php
    $data = "Hello";

    function sayHello(){
        echo $GLOBALS["data"];
    }

    sayHello();
?>

Я считаю это простым и понятным. $ GLOBALS - это то, как PHP позволяет вам ссылаться на глобальную переменную. Если вы использовали такие вещи, как $ _SERVER, $ _POST и т. Д., То вы ссылаетесь на глобальную переменную, не зная об этом.


Который из? $GLOBAL(текст) или $GLOBALS(образец кода)? (Пожалуйста, ответьте, отредактировав свой ответ , а не здесь, в комментариях (при необходимости).)
Питер Мортенсен

это $ GLOBALS, а не $ GLOBAL. Должна быть буква "S". Затем укажите имя вашей переменной как ключ к ассоциативному массиву.
Псалмы Калу

Обновите свой ответ, отредактировав его (чтобы начать редактирование , нажмите « изменить » между «поделиться» и «пометить» . Эти три находятся слева - слева от «отредактировано» и «ответил» после ответа сам, над этим комментарием и, прежде всего, три комментария здесь). Информация в комментариях может исчезнуть в любой момент. Это не форум - здесь можно (и нужно) обновлять информацию . Заранее большое спасибо.
Питер Мортенсен


0
<?php

    $data = 'My data';

    $menugen = function() use ($data) {

        echo "[ $data ]";
    };

    $menugen();
?>

Вы также можете упростить

echo "[" . $data . "]"

к

echo "[$data]"

echo "[" . $data . "]"и echo "[ $data ]"не совпадают (два лишних пробела в выводе для последнего).
Питер Мортенсен

0

По этой причине PHP может раздражать. Ответы выше с использованиемglobal не сработали для меня, и мне потребовалось некоторое время, чтобы понять, как правильно использовать use.

Это верно:

$functionName = function($stuff) use ($globalVar) {
 //do stuff
}
$output = $functionName($stuff);
$otherOutput = $functionName($otherStuff);

Это неверно:

function functionName($stuff) use ($globalVar) {
 //do stuff
}
$output = functionName($stuff);
$otherOutput = functionName($otherStuff);

Используя ваш конкретный пример:

    $data = 'My data';

    $menugen = function() use ($data) {
        echo "[" . $data . "]";
    }

    $menugen();

-1

Если хотите, вы можете использовать функцию «определить», но эта функция создает константу, которую нельзя изменить после определения.

<?php
    define("GREETING", "Welcome to W3Schools.com!");

    function myTest() {
        echo GREETING;
    }

    myTest();
?>

Константы PHP


Это определяет глобальную константу, а не переменную.
Beejor

3
После определения константы нельзя изменить.
Beejor
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.